Pandas transform() vs apply()
Я не понимаю, почему apply
и transform
возвращают разные типы данных при вызове в одном кадре данных. То, как я объяснял две функции себе, прежде чем что-то пошло в строке "apply
, разрушает данные, а transform
выполняет то же самое, что и apply
, но сохраняет исходный индекс и не сворачивается". Рассмотрим следующее.
df = pd.DataFrame({'id': [1,1,1,2,2,2,2,3,3,4],
'cat': [1,1,0,0,1,0,0,0,0,1]})
Пусть идентифицируют те id
, которые имеют ненулевую запись в столбце cat
.
>>> df.groupby('id')['cat'].apply(lambda x: (x == 1).any())
id
1 True
2 True
3 False
4 True
Name: cat, dtype: bool
Великий. Однако, если бы мы хотели создать столбец индикаторов, мы могли бы сделать следующее.
>>> df.groupby('id')['cat'].transform(lambda x: (x == 1).any())
0 1
1 1
2 1
3 1
4 1
5 1
6 1
7 0
8 0
9 1
Name: cat, dtype: int64
Я не понимаю, почему dtype теперь int64
вместо логического значения, возвращаемого функцией any()
.
Когда я изменяю исходный фрейм данных, чтобы содержать некоторые логические значения (обратите внимание, что нули остаются), подход преобразования возвращает логические значения в столбце object
. Это лишняя тайна для меня, поскольку все значения являются логическими, но они перечислены как object
, по-видимому, для соответствия dtype
исходного столбца смешанного типа целых чисел и булевых элементов.
df = pd.DataFrame({'id': [1,1,1,2,2,2,2,3,3,4],
'cat': [True,True,0,0,True,0,0,0,0,True]})
>>> df.groupby('id')['cat'].transform(lambda x: (x == 1).any())
0 True
1 True
2 True
3 True
4 True
5 True
6 True
7 False
8 False
9 True
Name: cat, dtype: object
Однако, когда я использую все логические значения, функция преобразования возвращает логический столбец.
df = pd.DataFrame({'id': [1,1,1,2,2,2,2,3,3,4],
'cat': [True,True,False,False,True,False,False,False,False,True]})
>>> df.groupby('id')['cat'].transform(lambda x: (x == 1).any())
0 True
1 True
2 True
3 True
4 True
5 True
6 True
7 False
8 False
9 True
Name: cat, dtype: bool
Используя мои острые навыки распознавания образов, кажется, что dtype
полученного столбца зеркалирует исходный столбец. Я был бы признателен за любые подсказки о том, почему это происходит или что происходит под капотом в функции transform
. Приветствия.
Ответы
Ответ 1
Похоже, что SeriesGroupBy.transform()
пытается применить результат dtype к тому же, что и исходный столбец, но DataFrameGroupBy.transform()
, похоже, не делает этого:
In [139]: df.groupby('id')['cat'].transform(lambda x: (x == 1).any())
Out[139]:
0 1
1 1
2 1
3 1
4 1
5 1
6 1
7 0
8 0
9 1
Name: cat, dtype: int64
# v v
In [140]: df.groupby('id')[['cat']].transform(lambda x: (x == 1).any())
Out[140]:
cat
0 True
1 True
2 True
3 True
4 True
5 True
6 True
7 False
8 False
9 True
In [141]: df.dtypes
Out[141]:
cat int64
id int64
dtype: object
Ответ 2
Просто добавьте еще один иллюстративный пример с суммой, поскольку я нахожу это более явным:
df = (
pd.DataFrame(pd.np.random.rand(10, 3), columns=['a', 'b', 'c'])
.assign(a=lambda df: df.a > 0.5)
)
Out[70]:
a b c
0 False 0.126448 0.487302
1 False 0.615451 0.735246
2 False 0.314604 0.585689
3 False 0.442784 0.626908
4 False 0.706729 0.508398
5 False 0.847688 0.300392
6 False 0.596089 0.414652
7 False 0.039695 0.965996
8 True 0.489024 0.161974
9 False 0.928978 0.332414
df.groupby('a').apply(sum) # drop rows
a b c
a
False 0.0 4.618465 4.956997
True 1.0 0.489024 0.161974
df.groupby('a').transform(sum) # keep dims
b c
0 4.618465 4.956997
1 4.618465 4.956997
2 4.618465 4.956997
3 4.618465 4.956997
4 4.618465 4.956997
5 4.618465 4.956997
6 4.618465 4.956997
7 4.618465 4.956997
8 0.489024 0.161974
9 4.618465 4.956997
Однако при применении к pd.DataFrame
, а не к pd.GroupBy
объекту я не смог увидеть никакой разницы.