Pandas 转换()与应用()
Pandas transform() vs apply()
我不明白为什么 apply
和 transform
return 在同一数据帧上调用时有不同的数据类型。我在之前向自己解释这两个函数的方式类似于“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]})
让我们找出在 cat
列中具有非零条目的那些 id
。
>>> 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()
函数编辑的布尔值 return。
当我将原始数据框更改为包含一些布尔值(请注意零仍然存在)时,转换方法 returns 布尔值在 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
但是,当我使用所有布尔值时,转换函数 return 是一个布尔列。
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
似乎与原始列的 dtype
相同。我将不胜感激关于为什么会发生这种情况或 transform
函数中发生了什么的任何提示。干杯。
看起来 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
只是添加另一个带有 sum 的说明性示例,因为我发现它更明确:
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
对象时,我看不出有任何区别。
我不明白为什么 apply
和 transform
return 在同一数据帧上调用时有不同的数据类型。我在之前向自己解释这两个函数的方式类似于“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]})
让我们找出在 cat
列中具有非零条目的那些 id
。
>>> 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()
函数编辑的布尔值 return。
当我将原始数据框更改为包含一些布尔值(请注意零仍然存在)时,转换方法 returns 布尔值在 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
但是,当我使用所有布尔值时,转换函数 return 是一个布尔列。
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
似乎与原始列的 dtype
相同。我将不胜感激关于为什么会发生这种情况或 transform
函数中发生了什么的任何提示。干杯。
看起来 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
只是添加另一个带有 sum 的说明性示例,因为我发现它更明确:
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
对象时,我看不出有任何区别。