Применить против преобразования объекта групповой
рассмотрим следующий фрейм данных:
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
как вы можете видеть, фрейм данных передается в