pandas df.apply неожиданно меняет датафрейм на месте - PullRequest
0 голосов
/ 22 сентября 2018

Насколько я понимаю, pandas.DataFrame.apply не применяет изменения на месте, и мы должны использовать его возвращаемый объект для сохранения любых изменений.Однако я обнаружил следующее несоответствующее поведение:

Давайте применим фиктивную функцию для обеспечения того, чтобы исходный df оставался нетронутым:

>>> def foo(row: pd.Series):
...     row['b'] = '42'

>>> df = pd.DataFrame([('a0','b0'),('a1','b1')], columns=['a', 'b'])
>>> df.apply(foo, axis=1)
>>> df
    a   b
0   a0  b0
1   a1  b1

Это ведет себя как ожидалось.Тем не менее, foo применит изменения на месте, если мы изменим способ, которым мы инициализируем этот df:

>>> df2 = pd.DataFrame(columns=['a', 'b'])
>>> df2['a'] = ['a0','a1']
>>> df2['b'] = ['b0','b1']
>>> df2.apply(foo, axis=1)
>>> df2
    a   b
0   a0  42
1   a1  42

Я также заметил, что вышеприведенное неверно, если столбцы dtypes не имеют тип 'object'.Почему apply () ведет себя по-разному в этих двух контекстах?

Python: 3.6.5

Панды: 0.23.1

1 Ответ

0 голосов
/ 22 сентября 2018

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

Как вы правильно указали, apply не предназначен для использования для изменения фрейма данных.Однако, поскольку apply принимает произвольную функцию, это не гарантирует, что применение этой функции будет идемпотентным и не изменит кадр данных.Здесь вы нашли отличный пример такого поведения, потому что ваша функция foo пытается изменить строку, которую она передает apply.

Использование apply для изменения строки может привести кэти побочные эффекты.Это не лучшая практика.

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

import pandas as pd
# construct df2 just like you did
df2 = pd.DataFrame(columns=['a', 'b'])
df2['a'] = ['a0','b0']
df2['b'] = ['a1','b1']

df2['b_copy'] = df2.apply(lambda row: row['b'], axis=1) # apply to each row
df2['b_replace'] = df2.apply(lambda row: '42', axis=1) 
df2['b_reverse'] = df2['b'].apply(lambda val: val[::-1]) # apply to each value in b column

print(df2)

# output:
#     a   b b_copy b_replace b_reverse
# 0  a0  a1     a1        42        1a
# 1  b0  b1     b1        42        1b

Обратите внимание, что панды передали строку или ячейку функции, которую вы даете в качествеПервый аргумент apply, затем сохраняет выходные данные функции в столбце по вашему выбору.

Если вы хотите изменять строку данных построчно, взгляните на iterrows и loc для самого идиоматического маршрута.

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