Применить против преобразования объекта групповой
рассмотрим следующий фрейм данных:
A B C D
0 foo one 0.162003 0.087469
1 bar one -1.156319 -1.526272
2 foo two 0.833892 -1.666304
3 bar three -2.026673 -0.322057
4 foo two 0.411452 -0.954371
5 bar two 0.765878 -0.095968
6 foo one -0.654890 0.678091
7 foo three -1.789842 -1.130922
работают следующие команды:
> df.groupby('A').apply(lambda x: (x['C'] - x['D']))
> df.groupby('A').apply(lambda x: (x['C'] - x['D']).mean())
но ни одна из следующих работ:
> df.groupby('A').transform(lambda x: (x['C'] - x['D']))
ValueError: could not broadcast input array from shape (5) into shape (5,3)
> df.groupby('A').transform(lambda x: (x['C'] - x['D']).mean())
TypeError: cannot concatenate a non-NDFrame object
почему?пример по документации похоже, что вызов transform в группе позволяет выполнять обработку операций по строкам:
# Note that the following suggests row-wise operation (x.mean is the column mean)
zscore = lambda x: (x - x.mean()) / x.std()
transformed = ts.groupby(key).transform(zscore)
другими словами, Я думал, что преобразование по существу является конкретным типом применения (тот, который не делает совокупный.) Где я ошибаюсь?
для справки, ниже приведена конструкция исходного фрейма данных выше:
df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar',
'foo', 'bar', 'foo', 'foo'],
'B' : ['one', 'one', 'two', 'three',
'two', 'two', 'one', 'three'],
'C' : randn(8), 'D' : randn(8)})
2 ответа:
как я чувствовал себя так же путают с
.transformоперация против.applyя нашел несколько ответов пролить свет на этот вопрос. ответ например, было очень полезно.мой вынос до сих пор это
.transformбудет работать (или заниматься) сSeries(столбцы) в изоляции друг от друга. Это означает, что в ваших последних двух вызовах:df.groupby('A').transform(lambda x: (x['C'] - x['D'])) df.groupby('A').transform(lambda x: (x['C'] - x['D']).mean())Вы спрашивали
.transformчтобы взять значения из двух столбцов и "это" на самом деле не делает видеть их обоих одновременно (так сказать).transformбудет смотреть на столбцы dataframe один за другим и возвращать назад серию (или группу серий) "сделанных" из скаляров, которые повторяютсяlen(input_column)раза.Итак, этот скаляр, который должен использоваться
.transformсделатьSeriesявляется результатом некоторой функции сокращения, применяемой на входеSeries(и только по одной серии/колонке за раз).рассмотрим этот пример (на вашем таблицы данных):
zscore = lambda x: (x - x.mean()) / x.std() # Note that it does not reference anything outside of 'x' and for transform 'x' is one column. df.groupby('A').transform(zscore)даст:
C D 0 0.989 0.128 1 -0.478 0.489 2 0.889 -0.589 3 -0.671 -1.150 4 0.034 -0.285 5 1.149 0.662 6 -1.404 -0.907 7 -0.509 1.653что точно так же, как если бы вы использовали его только на одном столбце одновременно:
df.groupby('A')['C'].transform(zscore)урожайность:
0 0.989 1 -0.478 2 0.889 3 -0.671 4 0.034 5 1.149 6 -1.404 7 -0.509отметим, что
.applyв последнем примере (df.groupby('A')['C'].apply(zscore)) будет работать точно так же, но это не удастся, если вы попытаетесь использовать его на фрейме данных:df.groupby('A').apply(zscore)выдает ошибку:
ValueError: operands could not be broadcast together with shapes (6,) (2,)так где же еще
.transformполезное? Самый простой case пытается назначить результаты функции сокращения обратно в исходный фрейм данных.df['sum_C'] = df.groupby('A')['C'].transform(sum) df.sort('A') # to clearly see the scalar ('sum') applies to the whole column of the groupурожайность:
A B C D sum_C 1 bar one 1.998 0.593 3.973 3 bar three 1.287 -0.639 3.973 5 bar two 0.687 -1.027 3.973 4 foo two 0.205 1.274 4.373 2 foo two 0.128 0.924 4.373 6 foo one 2.113 -0.516 4.373 7 foo three 0.657 -1.179 4.373 0 foo one 1.270 0.201 4.373пробуем то же самое с
.applyдастNaNsнаsum_C. Потому что.applyвернул бы уменьшенныйSeries, который он не знает, как транслировать обратно:df.groupby('A')['C'].apply(sum)даем:
A bar 3.973 foo 4.373бывают также случаи, когда
.transformиспользуется для фильтрации данных:df[df.groupby(['B'])['D'].transform(sum) < -1] A B C D 3 bar three 1.287 -0.639 7 foo three 0.657 -1.179я надеюсь, что это добавляет немного большая ясность.
два основных различия между
applyиtransformесть два основных различия между
transformиapplyметоды groupby.
applyнеявно передает все столбцы для каждой группы как DataFrame к пользовательской функции, в то время какtransformпроходит каждый столбец для каждой группы как серия к пользовательской функции- пользовательская функция передается в
applyможет возвращать скалярное, или ряд или фрейм данных (или массив numpy или даже список). Пользовательская функция передается вtransformдолжна возвращать последовательность (одномерный ряд, массив или список) той же длины, что и группа.и
transformработает только на одной серии за раз аapplyработает на весь фрейм данных сразу.проверка пользовательской функции
это может помочь совсем немного, чтобы проверить вход в пользовательскую функцию, переданную
applyилиtransform.примеры
давайте создадим некоторые примеры данных и проверим группы, чтобы вы могли видеть, о чем я говорю:
df = pd.DataFrame({'State':['Texas', 'Texas', 'Florida', 'Florida'], 'a':[4,5,1,3], 'b':[6,10,3,11]}) dfдавайте создадим простую пользовательскую функцию, которая выводит тип неявно переданного объекта, а затем вызывает ошибку, так что выполнение может быть остановлено.
def inspect(x): print(type(x)) raiseтеперь давайте передадим эту функцию как groupby
applyиtransformметоды, чтобы увидеть, какой объект передается это:df.groupby('State').apply(inspect) <class 'pandas.core.frame.DataFrame'> <class 'pandas.core.frame.DataFrame'> RuntimeErrorкак вы можете видеть, фрейм данных передается в