<p>pandas.DataFrame.query, чтобы разрешить имя столбца с пробелом</p>

Созданный на 28 февр. 2014  ·  41Комментарии  ·  Источник: pandas-dev/pandas

Было бы неплохо сделать что-то подобное

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

Я встречал много файлов внешних данных, в именах столбцов которых есть пробелы. Было бы неплохо иметь возможность проводить быстрый анализ данных без предварительного переименования столбцов.

API Design Indexing Reshaping

Самый полезный комментарий

R и dplyr используют обратную кавычку (``), чтобы заключить имена столбцов в кавычки с пробелом и специальными символами. Например:

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

Интересно, насколько сложно включить это в синтаксический анализатор pandas, чтобы такие функции, как query , eval или даже синтаксис df. могли работать с более общими именами столбцов?

Все 41 Комментарий

Хм. Многие наборы данных _do_ имеют эту проблему, но рассмотрите объем кода, необходимый для переименования столбцов, по сравнению с объемом кода, необходимым для синтаксического анализа этого нового синтаксиса (или чего-то подобного).

Переименовать столбцы просто:

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

Это хорошо протестировано и легко поддается отладке. Для более сложной замены можно использовать регулярные выражения.

То, что входит в синтаксический анализ, заметно менее прямолинейно:

  1. Как это будет токенизироваться? (Для меня это не так просто, может быть простой способ сделать это, но похоже, что вам придется создать новый токен, чтобы устранить неоднозначность синтаксической ошибки при построении списка, а затем сопоставить все это с действительным Идентификатор Python).
  2. Как бы это разобрать? (не слишком сложно, он анализирует как ColumnNode или какой-то другой объект, который просматривается как столбец во фрейме)

Что-то, что может быть полезно в качестве золотой середины, - это функция df = pd.clean_columns(df) , которая переименует ваши столбцы в допустимые идентификаторы Python, чтобы вам не пришлось слишком много думать об этом.

Я не уверен в реализации. Возможно, мы можем использовать обычные скобки вместо

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

В любом случае, метод clean_columns мне кажется хорошей идеей. Возможно, это также может быть аргумент ключевого слова в функции read_csv .

@socheon Давайте постараемся clean_columns аргумент read_csv , пожалуйста , открыть еще один вопрос.

@jreback Что вы думаете о функции верхнего уровня clean_columns ?

Я думаю, если вы поместите кавычки вокруг имени столбца, это может сработать на мастере

исправление для разрешения & и | заставляет обращаться с ними как с отдельными токенами

Он будет обрабатываться как строка, которая затем превращается во внутреннюю временную строку, так что это не сработает.

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

Может быть, разрешить ссылку на столбец в его чистой версии?

df.query("column_with_space > 2")

Я делаю эту очистку для автозаполнения всякий раз, когда это имеет смысл.

Имена столбцов с пробелами, точками, скобками и другими недопустимыми символами могут быть дополнительно автоматически заменены эквивалентными допустимыми символами, такими как подчеркивание. Это также очень удобно для доступа к столбцам как элементам фрейма данных с точечным синтаксисом.

Привет,
Я хочу дать обещание решить этот вопрос.

Для нас это очень важный вопрос. Бывают случаи, когда мы не можем изменить имена столбцов, потому что их нужно сохранить.

То, что pandas предъявляет произвольные требования к именам столбцов, является, IMHO, плохим дизайнерским решением и плохой практикой программирования.

Извините за жалобу, но я действительно думаю, что панды должны исправить эту проблему должным образом. Пожалуйста, примите это во внимание. Спасибо.

@dgua, вы можете отправить запрос на исправление. Обратите внимание, что на самом деле .query - это просто удобный интерфейс, на самом деле он имеет очень конкретные гарантии, что означает, что он предназначен для синтаксического анализа, как язык запросов, а не полностью общий интерфейс.

В любом случае рекомендуемым «основным» способом индексации всегда был:

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, я с тобой согласен. Тем не менее, у нас есть люди, которые широко используют .query в своем коде, потому что он проще / читабельнее, поэтому сейчас мы находимся в затруднительном положении: либо изменить весь этот код, либо переименовать столбцы, ни то, ни другое нежелательно. .

@dgua, как я уже сказал, это можно сделать по запросу сообщества. У меня просто нет времени.

R и dplyr используют обратную кавычку (``), чтобы заключить имена столбцов в кавычки с пробелом и специальными символами. Например:

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

Интересно, насколько сложно включить это в синтаксический анализатор pandas, чтобы такие функции, как query , eval или даже синтаксис df. могли работать с более общими именами столбцов?

Мне нравится предложение zhiruiwang, и я смотрю на его положительные отзывы других.

Итак, я немного изучил код, и в основном pandas выполняет некоторую предварительную обработку выражения и передает его в numexpr. Рядом с этим передается localdict, содержащий, среди прочего, имена столбцов фрейма данных.

Я думал просто изменить выражение, заменив каждый пробел в обратных кавычках на что-то другое (например, "_" или что-то менее используемое для предотвращения конфликтов имен) и удалить обратные кавычки. Это создает допустимое выражение для numexpr. Затем сделайте то же самое с пробелами в именах столбцов, когда они передаются преобразователям, которые в конечном итоге составляют localdict, чтобы правильные имена все еще можно было найти с помощью numexpr.

Может быть, код, который это сделает, может выглядеть так, но я его не тестировал. Сначала мне нравится слышать, что другие думают об этой идее.

# 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

РЕДАКТИРОВАТЬ: исправлено _replace_spaces_backtickvariables (регулярное выражение должно было быть ленивым)

@zhiruiwang Синтаксис df. не сможет использовать это, так как он анализируется Python, но query и eval будут работать.

@jreback Вы, кажется,

Что вы думаете о моем подходе, описанном в предыдущем комментарии?

Вместо этого мы также могли решить ее, как предлагал далелунг. Так что разрешите "грязным" именам ссылаться на их "чистые" имена (на "это имя столбца" можно ссылаться с помощью "this_column_name" без фактического изменения имени столбца) и вообще не используйте "инкапсуляцию".

Для этого потребуется изменить только эту единственную строку. (Если я правильно понимаю код, не проверял.)

# 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

Что вы думаете? Какой подход вы считаете лучшим?

Затем я могу попытаться сделать для него запрос на перенос.

Это было бы неплохо, но я решаюсь с помощью таких команд:

Заменить пустое пространство

df.rename (columns = {k: k.replace ('', '_') для k в df.columns, если k.count ('')> 0}, inplace = 1)

Начинается с числового значения

df.rename (columns = {k: '_' + k для k в df.columns, если k [0] .isdigit ()}, inplace = 1)

Извините, но это неудовлетворительно. Как мне вернуться к исходным столбцам? Что, если «_» также используется как часть имени столбца?

Пользователи не должны этого делать, и это серьезная проблема панд.

DG

19 января 2019 г. в 11:49 bscully27 [email protected] написал:

Это было бы неплохо, но я решаюсь с помощью таких команд:

Заменить пустое пространство

df.rename (columns = {k: k.replace ('', '_') для k в df.columns, если k.count ('')> 0}, inplace = 1)

Начинается с числового значения

df.rename (columns = {k: '_' + k для k в df.columns, если k [0] .isdigit ()}, inplace = 1)

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub https://github.com/pandas-dev/pandas/issues/6508#issuecomment-455809809 или отключите поток https://github.com/notifications/unsubscribe-auth/ ADtPtKBTb6T5ErsqMrQYFSVblj8eYOTKks5vE3a3gaJpZM4Bl2In .

в sql вы просто используете квадратные скобки, и это приятно.

@dgua у вас есть время Предложение @zhiruiwang об использовании обратных кавычек кажется разумным, если оно может быть реализовано (мы не могли использовать их раньше, поскольку они уже имеют значение в Python 2).

@TomAugspurger У меня было бы немного времени после экзаменов, и я уже

  • Что должно быть в SEPERATOR_REPLACING_SPACES ? Если мы выберем просто «_» вместо более сложной строки замены, это может помешать уже существующим другим столбцам, но если мы выберем «_», у него есть дополнительная функция, которую вы можете ссылаться на this column name помощью `this column name` _and_ this_column_name . (Мы могли бы даже отказаться от использования обратных кавычек.)

  • SEPERATOR_REPLACING_SPACES должен быть согласован для двух файлов. Итак, следует ли его объявить где-то еще и импортировать в эти файлы, чтобы убедиться, что они одинаковы, или будет достаточно простого комментария, упоминающего это?

  • В коде, который я изменю, используется callable() . callable() недоступен в версиях 3.0–3.2, поэтому следует ли мне исправить это в то же время?

Я не знаком с этим кодом, так что вы можете быть здесь экспертом :)

В коде, который я изменю, используется callable (). callable () недоступен в версиях 3.0-3.2

Python 3.0 - 3.2? Нам требуется 3.5+

Я думаю, что идея обратной кавычки сейчас довольно хороша, поскольку в контексте eval или query вам не нужно беспокоиться о том, как что-то реализовано. Я бы не хотел его бросать.

Для простого контекста Python новые имена могут иметь префикс или суффикс для предотвращения коллизий (например, все они заканчиваются знаком подчеркивания).

иметь префикс или суффикс для предотвращения столкновений

@beojan: да, но, возможно, вы можете рассматривать эти "столкновения" как особенность. Таким образом, вы можете ссылаться на this column name помощью `this column name` _and_ this_column_name . Я также думаю, что это немного глупо, если у вас есть два имени столбца this column name и this_column_name , но вы никогда не знаете.

Вы можете использовать this_column_name_ .

Если у вас действительно есть два сталкивающихся столбца, я не понимаю, почему это особенность.

Хорошо, если у меня есть датафрейм:

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

Теперь, когда эта функция реализована без мер по предотвращению столкновений, я могу сказать:

df.query(column_name > 3)

И панды автоматически будут ссылаться на «имя столбца» в этом запросе. Это также ранее было предложено Даледжунгом. Теперь вы также можете оставить поддержку для обратных кавычек.

Я также не думаю, что вы увидите какие-либо фреймы данных _ в дикой природе_, которые выглядят так:

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

Столкновения могут вызвать проблемы.

Так что, на мой взгляд, это не вызовет каких-либо столкновений и дает дополнительный способ ссылки на столбец.

Я не думаю, что мы были бы заинтересованы в частичной поддержке этого. Смысл
PR был бы полностью избежать двусмысленности,
так что последний пример должен работать.

В среду, 23 января 2019 г., в 10:56 hwalinga [email protected] написал:

Хорошо, если у меня есть датафрейм:

"column name" "name"

1 4 5
2 2 1

С реализованной функцией, без мер по предотвращению столкновений, теперь я могу
сказать:

df.query (имя_столбца> 3)

И панды автоматически будут ссылаться на «имя столбца» в этом запросе. Этот
также ранее был предложен dalejung. Теперь вы также можете оставить поддержку
для обратных кавычек.

Я также не думаю, что вы увидите в дикой природе какие-либо фреймы данных, которые выглядят
как:

"column name" "name" "column_name"

1 3 5 6
2 2 1 9

Столкновения могут вызвать проблемы.

Так что, на мой взгляд, это не вызовет никаких столкновений и даст дополнительный способ
см. столбец.

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/pandas-dev/pandas/issues/6508#issuecomment-456880863 ,
или отключить поток
https://github.com/notifications/unsubscribe-auth/ABQHIkl6f9IgUGBKlzranZpsOe3atH3Aks5vGJQ7gaJpZM4Bl2In
.

@TomAugspurger Хорошо, это ясно.

Следует ли использовать суффикс типа «_» для предотвращения коллизий или же заменить пробел между именами столбцов сложной строкой, чтобы исключить еще более случайные коллизии.

это может работать прямо в AST
Я думаю, что они на самом деле разбираются правильно, но мы неправильно обрабатываем повторную сборку

Всем привет,

Есть ли график, когда будет выпущена эта функция?

Я думаю, что это сделано в мастере, учитывая упомянутую выше фиксацию.

это будет через 0,25 - проб через месяц или 2

Не хочу портить веселье, но чтобы избежать разочарований: Pandas 0.25 будет доступен только для Python3. Также см. Https://pandas-docs.github.io/pandas-docs-travis/install.html#install -dropping-27.

@jreback Спасибо за информацию. Я видел, что рубеж 0,25,0 намечен на 1 мая.

@hwalinga Не беспокойся. Это будет использоваться только в базе кода Python3.

Это было бы хорошей возможностью разрешить имя столбца, содержащее точки. Почему это не было включено?

@danielhrisca

Я реализовал это, и мы не думали об этом. Вы можете открыть новый вопрос, чтобы поднять его снова. Может быть, есть веская причина, о которой я не знаю, но специалисты по сопровождению считают, что этого лучше не допускать.

Думаю, я смогу реализовать это снова. Однако у него не будет такого же решения, как у пространства. Причина в том, что строка запроса анализируется как исходный код Python. Вы должны применить обходные пути, если хотите, чтобы определенный синтаксис интерпретировался по-другому. И кастомного парсера для этой функции, наверное, не будет.

@hwalinga Привет
Я столкнулся с той же проблемой, но имя таблицы - точка

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

Я видел изменения, которые вы внесли в 0.25.0.
У меня есть предложение,
Когда я прочитал исходный код программного обеспечения Perl Annovar, я обнаружил, что для представления специальных символов можно использовать шестнадцатеричные числа.
фг

comsic=comsic\x3dxxxxxxxxxxxxxxxxxxx

Используйте функцию для соответствия специальным символам ввода и вывода при разборе

@zhaohongqiangsoliva

Не думаю, что понимаю, что вы пытаетесь сказать. Не могли бы вы подробнее рассказать о проблеме, которую хотите решить?

@hwalinga
Извините, я не очень хорошо владею английским. Моя проблема в том, что проблема пробелов между именами столбцов теперь решена, но другие символы все еще не решены, например

.      /           \     

и я даю предлагаемое изменение - использовать Hex

Я поддерживаю это. В именах столбцов должен быть разрешен ЛЮБОЙ символ.

Спасибо.

22 июня 2019 г., в 18:01, zhaohongqiangsoliva [email protected] написал:

@hwalinga https://github.com/hwalinga
Извините, я не очень хорошо владею английским. Моя проблема в том, что проблема пробелов между именами столбцов теперь решена, но другие символы все еще не решены, например

. / \
и я даю предлагаемое изменение - использовать Hex

-
Вы получаете это, потому что вас упомянули.
Ответить на это сообщение непосредственно, просматривать его на GitHub https://github.com/pandas-dev/pandas/issues/6508?email_source=notifications&email_token=AA5U7NAIAJXVHI7LYXNCGNDP33DO5A5CNFSM4AMXMIT2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYKUG3I#issuecomment-504709997 или приглушить нить https://github.com/ уведомления / unsubscribe-auth / AA5U7NCACMBXVVQT7Z4DUE3P33DO5ANCNFSM4AMXMITQ .

@dgua @zhaohongqiangsoliva

Проблема в том, что запрос должен стать допустимым выражением Python. Использование шестнадцатеричного кода для запрещенных символов не решит эту проблему. Разрешение пробелов в имени уже основано на взломе функции токенизации ( from tokenize import generate_tokens ). Я не думаю, что невозможно разрешить больше символов в имени, но это будет основано на повторном взломе функции токенизации. (Pandas не будет использовать собственный парсер Python.)

Если вы действительно этого хотите, вы, конечно, можете открыть новую проблему, решающую эту проблему, и если вы отметите меня в этой проблеме, я объясню свое решение сопровождающим.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги