<p>pandas.DataFrame.query para permitir el nombre de la columna con espacio</p>

Creado en 28 feb. 2014  ·  41Comentarios  ·  Fuente: pandas-dev/pandas

Ser capaz de hacer algo como esto sería bueno

df.query('[col with space] < col')

Encontré muchos archivos de datos externos que tienen espacios en los nombres de las columnas. Sería bueno poder hacer un análisis rápido de los datos sin antes cambiar el nombre de las columnas.

API Design Indexing Reshaping

Comentario más útil

R y dplyr usan comillas inversas (``) para citar los nombres de las columnas con espacios y caracteres especiales. Por ejemplo:

df$`column with space`
df %>%
    mutate(`column with space` = 1)

Me pregunto qué tan difícil es incorporar esto en el analizador de pandas, de modo que funciones como query , eval o incluso df. dot sintaxis puedan lidiar con nombres de columna más generales.

Todos 41 comentarios

Hm. Muchos conjuntos de datos _do_ tienen este problema, pero considere la cantidad de código necesario para cambiar el nombre de las columnas frente a la cantidad de código necesario para analizar esa nueva sintaxis (o algo similar).

Cambiar el nombre de las columnas es sencillo:

cols = df.columns
cols = cols.map(lambda x: x.replace(' ', '_') if isinstance(x, (str, unicode)) else x)
df.columns = cols

Esto está bien probado y es fácil de depurar. Para un reemplazo más complicado, puede usar expresiones regulares.

Las cosas que entran en el análisis son mucho menos sencillas:

  1. ¿Cómo se convertiría en token? (Esto no es tan sencillo para mí, podría haber una manera fácil de hacerlo, pero parece que tendrías que crear un nuevo token para eliminar la ambigüedad de un error de sintaxis de la construcción de la lista y luego mapear todo a un código válido. Identificador de Python).
  2. ¿Cómo analizaría esto? (no es demasiado difícil, se analiza como ColumnNode o algún objeto similar que se busca como una columna en el marco)

Algo que podría ser útil como medio feliz es una función df = pd.clean_columns(df) que cambiará el nombre de sus columnas para que sean identificadores de Python válidos para que no tenga que pensar demasiado en ello.

No estoy seguro de la implementación. Tal vez podamos usar corchetes normales en su lugar como

df.query('(col with space) < col')

De todos modos, el método clean_columns parece una buena idea. Quizás también podría ser un argumento de palabra clave en la función read_csv .

@socheon Tratemos de mantener nuestra discusión en un solo tema (¡yo también tiendo a clean_columns en read_csv , abra otro problema.

@jreback ¿Qué opinas de una función clean_columns nivel superior?

Creo que si pones comillas alrededor del nombre de la columna, podría funcionar en el maestro

la solución para permitir & y | hace que estos sean tratados como tokens individuales

Se tratará como una cadena, que luego se convertirá en un temporal interno para que no funcione.

df.query("'a column with a space' > 2") -> df.query("tmp_var_str_some_hex_value > 2")

¿Quizás permitir que la columna sea referenciada por su versión limpia?

df.query("column_with_space > 2")

Hago esta limpieza para el autocompletado siempre que tiene sentido.

Los nombres de columna con espacios, puntos, corchetes y otros caracteres no válidos se pueden reemplazar automáticamente por caracteres válidos equivalentes, como el subrayado. Esto también es muy útil para acceder a las columnas como miembros de un marco de datos con sintaxis de puntos.

Hola,
Quiero comprometerme a resolver este problema.

Es un tema muy importante para nosotros. Hay casos en los que no podemos cambiar los nombres de las columnas porque es necesario conservarlos.

Que pandas imponga un requisito arbitrario en los nombres de las columnas es, en mi humilde opinión, una mala decisión de diseño y una mala práctica de programación.

Perdón por quejarme, pero realmente creo que los pandas deberían solucionar este problema correctamente. Por favor consideralo. Gracias.

@dgua, puede enviar una solicitud de extracción para corregir. Tenga en cuenta que, en realidad, .query es solo una interfaz agradable de tener, de hecho, tiene garantías muy específicas, lo que significa que está diseñada para analizar como un lenguaje de consulta y no una interfaz completamente general.

En cualquier caso, la forma 'principal' recomendada de indexación siempre ha sido:

In [10]: df = DataFrame({'foo bar': [1, 2, 3, 4]})

In [11]: df[df['foo bar'] > 2]
Out[11]: 
   foo bar
2        3
3        4

jreback, estoy de acuerdo contigo. Sin embargo, tenemos personas que usan .query extensamente en su código porque es más fácil / más legible, por lo que ahora estamos en un dilema para cambiar todo ese código o cambiar el nombre de las columnas, ninguna de las cuales es deseable. .

@dgua, como dije, una solicitud de extracción de la comunidad haría esto. Simplemente no tengo tiempo.

R y dplyr usan comillas inversas (``) para citar los nombres de las columnas con espacios y caracteres especiales. Por ejemplo:

df$`column with space`
df %>%
    mutate(`column with space` = 1)

Me pregunto qué tan difícil es incorporar esto en el analizador de pandas, de modo que funciones como query , eval o incluso df. dot sintaxis puedan lidiar con nombres de columna más generales.

Me gusta la propuesta de zhiruiwang y mirar sus votos a favor que otros hacen.

Así que he examinado un poco el código y, básicamente, los pandas preprocesan la expresión y la pasan a numexpr. A continuación, se pasa con él un localdict que contiene, entre otros, los nombres de las columnas del marco de datos.

Estaba pensando en modificar la expresión reemplazando cada espacio entre comillas inversas por otra cosa (como "_" o algo menos utilizado para evitar conflictos de nombres) y eliminar las comillas inversas. Esto crea una expresión válida para numexpr. Además de eso, haga lo mismo con los espacios en los nombres de las columnas cuando se pasan a los resolutores que eventualmente componen el localdict, de modo que los nombres correctos aún se puedan encontrar mediante numexpr.

Quizás el código que hará esto pueda verse así, pero no lo he probado. Primero me gusta escuchar lo que otros piensan de la idea.

# Don't know if "_" is a good choice and don't know where to place this variable, 
# since it has to be constant in two different files and ideally is only defined once.
SEPERATOR_REPLACING_SPACES = "_"

# Replace spaces in variables surrounded by backticks:
# pandas/pandas/core/computation/expr.py 

import re

...

# new function
def _replace_spaces_backtickvariables(source):
    return re.sub(r'`(.*?)`', 
                  lambda m: m.group(1).replace(" ", SEPERATOR_REPLACING_SPACES), 
                  source)

...

# adjusted function
def _preparse(source, f=compose(_replace_locals, _replace_booleans,
                                _rewrite_assign), g=lambda x: x):
    ...
    g : callable
        This takes a source string and returns an altered one
    ...
    assert callable(g), 'g must be callable'
    source = g(source)

...

# adjusted class
class PandasExprVisitor(BaseExprVisitor):

    def __init__(self, env, engine, parser,
                 preparser=partial(_preparse, 
                                   f=compose(_replace_locals, _replace_booleans)
                                   g=_replace_spaces_backtickvariables)):

# Replace spaces in column names when passed to the localdict:
# pandas/pandas/core/frame.py

# adjusted function
def eval(self, expr, inplace=False, **kwargs):
    ...
    # line 3076
    resolvers = dict((k.replace(" ", SEPERATOR_REPLACING_SPACES), v) 
                     for k, v in self.iteritems()), index_resolvers

EDITAR: fijo _replace_spaces_backtickvariables (la expresión regular debería haber sido perezosa)

@zhiruiwang La df. no podrá usar esto ya que es analizada por Python, pero query y eval funcionarían.

@jreback Pareces ser el que más sabe sobre esto.

¿Qué opinas de mi enfoque explicado en el comentario anterior?

En cambio, también podríamos decidir resolverlo como propuso dalelung. Así que permita que los nombres "sucios" sean referidos por sus nombres "limpios" ("este nombre de columna" puede ser referido por "this_column_name" sin que la columna realmente cambie el nombre) y no use la encapsulación `` en absoluto.

Esto solo requeriría que se cambiara esta única línea. (Si entiendo el código correctamente, no lo he probado).

# Replace spaces in column names when passed to the localdict:
# pandas/pandas/core/frame.py

# adjusted function
def eval(self, expr, inplace=False, **kwargs):
    ...
    # line 3076
    resolvers = dict((k.replace(" ", SEPERATOR_REPLACING_SPACES), v) 
                     for k, v in self.iteritems()), index_resolvers

¿Qué piensas? ¿Qué enfoque crees que es mejor?

Entonces puedo intentar hacer una solicitud de extracción.

Esta característica sería buena pero la resuelvo con comandos como estos:

Reemplazar espacio en blanco

df.rename (columnas = {k: k.replace ('', '_') para k en gl.columns if k.count ('')> 0}, inplace = 1)

Comienza con valor numérico

gl.rename (columnas = {k: '_' + k para k en gl.columns si k [0] .isdigit ()}, inplace = 1)

Lo siento, pero eso es insatisfactorio. ¿Cómo vuelvo a las columnas originales? ¿Qué pasa si '_' también se usa como parte del nombre de una columna?

Los usuarios no deberían tener que hacer esto y es un problema grave de los pandas.

DG

El 19 de enero de 2019, a las 11:49, bscully27 [email protected] escribió:

Esta característica sería buena pero la resuelvo con comandos como estos:

Reemplazar espacio en blanco

df.rename (columnas = {k: k.replace ('', '_') para k en gl.columns if k.count ('')> 0}, inplace = 1)

Comienza con valor numérico

gl.rename (columnas = {k: '_' + k para k en gl.columns si k [0] .isdigit ()}, inplace = 1)

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub https://github.com/pandas-dev/pandas/issues/6508#issuecomment-455809809 , o silencie el hilo https://github.com/notifications/unsubscribe-auth/ ADtPtKBTb6T5ErsqMrQYFSVblj8eYOTKks5vE3a3gaJpZM4Bl2In .

en sql, solo usa corchetes y eso es bueno.

@dgua ¿tienes tiempo para enviar un PR? La sugerencia de @zhiruiwang de usar

@TomAugspurger Tendría algo de tiempo después de mis exámenes y ya

  • ¿Qué debería ser SEPERATOR_REPLACING_SPACES ? Si seleccionamos solo "_", en lugar de una cadena de reemplazo más compleja, podría interferir con otras columnas ya existentes, pero si elegimos "_" tiene la característica adicional de que puede referirse a this column name por `this column name` _and_ this_column_name . (Incluso podríamos eliminar la función de comillas inversas).

  • SEPERATOR_REPLACING_SPACES tiene que ser coherente en dos archivos. Entonces, ¿debería declararse en otro lugar e importarse en estos archivos para asegurarse de que sean iguales, o sería suficiente un simple comentario que mencione esto?

  • En el código que modificaré, se usa callable() . callable() no está disponible en 3.0-3.2, así que ¿debería arreglar esto también al mismo tiempo?

No estoy familiarizado con este código, por lo que puede ser el experto aquí :)

En el código que alteraré, se usa invocable (). callable () no está disponible en 3.0-3.2

Python 3.0 - 3.2? Requerimos 3.5+

Creo que la idea de las comillas inversas es bastante buena ahora, ya que en el contexto eval o query no tendrías que preocuparte por cómo se implementan las cosas. No querría dejarlo.

Para el contexto simple de Python, los nuevos nombres podrían tener un prefijo o sufijo para evitar colisiones (por ejemplo, todos terminan con un guión bajo).

tener un prefijo o sufijo para evitar colisiones

@beojan sí, pero tal vez puedas ver esas "colisiones" como una característica. Entonces puede hacer referencia a this column name por `this column name` _and_ this_column_name . También creo que es un poco tonto si tienes dos columnas con los nombres this column name y this_column_name , pero nunca se sabe.

Puede usar this_column_name_ .

Sin embargo, si realmente tiene dos columnas en colisión, no veo cómo eso es una característica.

Bueno, si tengo un marco de datos:

    "column name" "name"
1   4              5
2   2              1

Con la función implementada, sin medidas para colisionar, ahora puedo decir:

df.query(column_name > 3)

Y los pandas se referirían automáticamente al "nombre de la columna" en esta consulta. Esto también fue sugerido anteriormente por dalejung. Ahora también puede dejar el soporte para comillas invertidas.

Tampoco creo que vea ningún marco de datos _en la naturaleza_ que se parezca a:

    "column name" "name" "column_name"
1   3              5     6
2   2              1     9

En el que las colisiones causarían un problema.

Entonces, en mi opinión, no causará ninguna colisión y brinda una forma adicional de referirse a la columna.

No creo que nos interese apoyar parcialmente esto. El punto de
el PR sería evitar por completo la ambigüedad,
por lo que el último ejemplo debería funcionar.

El miércoles 23 de enero de 2019 a las 10:56 a.m., hwalinga [email protected] escribió:

Bueno, si tengo un marco de datos:

"column name" "name"

1 4 5
2 2 1

Con la función implementada, sin medidas para colisionar, ahora puedo
decir:

df.query (nombre_columna> 3)

Y los pandas se referirían automáticamente al "nombre de la columna" en esta consulta. Esta
también fue sugerido anteriormente por dalejung. Ahora también puedes dejar el soporte
para las comillas invertidas.

Tampoco creo que vea ningún marco de datos
me gusta:

"column name" "name" "column_name"

1 3 5 6
2 2 1 9

En el que las colisiones causarían un problema.

Por lo tanto, en mi opinión, no causará ninguna colisión y ofrece una forma adicional de
consulte la columna.

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/pandas-dev/pandas/issues/6508#issuecomment-456880863 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/ABQHIkl6f9IgUGBKlzranZpsOe3atH3Aks5vGJQ7gaJpZM4Bl2In
.

@TomAugspurger Está bien, eso está claro.

¿Seguimos con un sufijo como "_" para evitar colisiones, o sustituimos el espacio entre los nombres de las columnas con una cadena compleja, para descartar incluso más colisiones accidentales?

esto podría funcionar directamente en el AST
Creo que estos realmente se analizan correctamente, pero no manejamos el reensamblaje correctamente

Hola a todos,

¿Existe un cronograma de cuándo se lanzará esta función?

Creo que está hecho en master, dado el compromiso mencionado anteriormente.

esto será en 0.25 - probablemente en un mes o 2

No quiero arruinar la diversión, pero para evitar decepciones: Pandas 0.25 solo estará disponible para Python3. Consulte también https://pandas-docs.github.io/pandas-docs-travis/install.html#install -dropping-27

@jreback Gracias por la información. Vi que el hito 0.25.0 vence el 1 de mayo.

@hwalinga No te preocupes. Esto se usará solo en la base de código de Python3.

Esta habría sido una buena oportunidad para permitir nombres de columna que contengan puntos. ¿Por qué no se incluyó esto?

@danielhrisca

Implementé esto y no pensamos en ello. Puede abrir un nuevo problema para que vuelva a aparecer. Puede haber una buena razón de la que no tenga conocimiento, pero los mantenedores sí, de que es mejor no permitirlo.

Creo que puedo implementarlo nuevamente. Sin embargo, no tendrá la misma solución que el espacio. La razón es que la cadena de consulta se analiza como código fuente de Python. Debe aplicar soluciones alternativas si desea que cierta sintaxis se interprete de manera diferente. Y probablemente no se implementará un analizador personalizado para esta función.

@hwalinga HI
Me he encontrado con el mismo problema, pero el nombre de la tabla es point

snv_df.query('Gene.refGene in ["MSH2","MSH3","MLH1","MLH3","MSH6","PMS2","PMS3"]'

Vi los cambios que hizo en 0.25.0.
Tengo una sugerencia,
Cuando leí el código fuente de un software de perl annovar, descubrí que puede usar hexadecimal para representar símbolos especiales.
fg

comsic=comsic\x3dxxxxxxxxxxxxxxxxxxx

Utilice una función para corresponder a los símbolos especiales de entrada y salida al analizar

@zhaohongqiangsoliva

No creo que entiendo lo que estás tratando de decir. ¿Puede explicar un poco más el problema que desea resolver?

@hwalinga
Lo siento, mi inglés no es bueno. Mi problema es que el problema de los espacios entre los nombres de las columnas ya está resuelto, pero aún no se resuelven otros símbolos, por ejemplo

.      /           \     

y doy un cambio propuesto es usar Hex

Secundo esto. Se debe permitir CUALQUIER carácter en los nombres de las columnas.

Gracias.

El 22 de junio de 2019, a las 18:01, zhaohongqiangsoliva [email protected] escribió:

@hwalinga https://github.com/hwalinga
Lo siento, mi inglés no es bueno. Mi problema es que el problema de los espacios entre los nombres de las columnas ya está resuelto, pero aún no se resuelven otros símbolos, por ejemplo

. / \
y doy un cambio propuesto es usar Hex

-
Recibes esto porque te mencionaron.
Responder a este correo electrónico directamente, visualizarla en GitHub https://github.com/pandas-dev/pandas/issues/6508?email_source=notifications&email_token=AA5U7NAIAJXVHI7LYXNCGNDP33DO5A5CNFSM4AMXMIT2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYKUG3I#issuecomment-504709997 , o silenciar el hilo https://github.com/ notificaciones / unsubscribe-auth / AA5U7NCACMBXVVQT7Z4DUE3P33DO5ANCNFSM4AMXMITQ .

@dgua @zhaohongqiangsoliva

El problema es que la consulta debe convertirse en una expresión de Python válida. Usar hexadecimal para caracteres no permitidos no resolverá este problema. Permitir espacios en el nombre ya se basa en piratear la función tokenizar ( from tokenize import generate_tokens ). No creo que sea imposible permitir más caracteres en el nombre, pero se basará en piratear la función de tokenizar nuevamente. (Pandas no utilizará su propio analizador de Python).

Si realmente desea esto, por supuesto, puede abrir un nuevo problema que aborde esto, y si me etiqueta en el problema, explicaré mi solución a los mantenedores.

¿Fue útil esta página
0 / 5 - 0 calificaciones