Вставка списка в ячейку - почему loc действительно работает здесь? - PullRequest
0 голосов
/ 28 января 2019

Нам известно, что стандартным методом установки одной ячейки является at или iat.Тем не менее, я заметил интересное поведение, которое мне было интересно, может ли кто-нибудь объяснить.

При решении этого вопроса я сталкиваюсь со странным поведением loc.

# Setup.

pd.__version__
# '0.24.0rc1'

df = pd.DataFrame({'A': [12, 23], 'B': [['a', 'b'], ['c', 'd']]})
df
    A       B
0  12  [a, b]
1  23  [c, d]

Чтобы установить ячейку (1, 'B'), достаточносделать это с помощью, как df.at[1, 'B'] = ....Но с помощью loc я сначала попробовал это, но это не сработало:

df.loc[1, 'B'] = ['m', 'n', 'o', 'p'] 
# ValueError: Must have equal len keys and value when setting with an iterable

Итак, я попробовал (что тоже не удалось)

df.loc[1, 'B'] = [['m', 'n', 'o', 'p']]
# ValueError: Must have equal len keys and value when setting with an ndarray

Я думал, что loc тоже будет как-товозможность взять вложенные списки здесь.При странном повороте событий этот код работал:

df.loc[1, 'B'] = [['m'], ['n'], ['o'], ['p']]
df

    A             B
0  12        [a, b]
1  23  [m, n, o, p]

Почему loc работает таким образом?Кроме того, если вы добавляете другой элемент в любой из списков, он проваливается:

df.loc[1, 'B'] = [['m'], ['n'], ['o'], ['p', 'q']]
# ValueError: Must have equal len keys and value when setting with an iterable

Пустые списки также не работают.Кажется бессмысленным вкладывать каждый элемент в свой список.

Почему loc делает это?Это задокументированное поведение или ошибка?

1 Ответ

0 голосов
/ 30 января 2019

Это происходит потому, что loc выполняет связку проверки всех вариантов использования, которые он поддерживает.(Примечание: история состояла в том, что loc и iloc были созданы для устранения неоднозначности ix, еще в 2013 v0.11, но даже сегодня в loc все еще остается много неоднозначности.)

В этом случае df.loc[1, 'B'] может либо вернуть:

  • отдельный элемент (как в этом случае, когда для 1 / 'B' существует уникальный индекс / столбец).
  • a Серия (если ЛИБО один из 1 / 'B' появляется в индексе / столбцах несколько раз).
  • a DataFrame (если ОБА 1 / 'B' появляется в индексе / столбцах несколько раз).

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

Так что pandas должен поддерживать все эти случаи для назначения!

Ранняя часть логики назначения преобразует список (списков) в пустой массив:

In [11]: np.array(['m', 'n', 'o', 'p']).shape
Out[11]: (4,)

In [12]: np.array([['m', 'n', 'o', 'p']]).shape
Out[12]: (1, 4)

Таким образом, вы не можете просто передать список списков и ожидать получить правильный массив.Вместо этого вы могли бы явно установить в массив объектов:

In [13]: a = np.empty(1, dtype=object)

In [14]: a[0] = ['m', 'n', 'o', 'p']

In [15]: a
Out[15]: array([list(['m', 'n', 'o', 'p'])], dtype=object)

Теперь вы можете использовать это в присваивании:

In [16]: df.loc[0, 'B'] = a

In [17]: df
Out[17]:
    A             B
0  12  [m, n, o, p]
1  23        [c, d]

Это все еще не идеально, но повторять, так многоВ крайних случаях в loc и iloc решение должно быть как можно более явным, чтобы их избежать (используйте at здесь).И вообще, как вы знаете, избегайте использования списков внутри DataFrame!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...