【问题标题】:Pandas transform() vs apply()熊猫变换()与应用()
【发布时间】:2017-05-19 11:43:51
【问题描述】:

我不明白为什么applytransform 在同一个数据帧上调用时会返回不同的数据类型。我之前向自己解释这两个函数的方式类似于“apply 折叠数据,transformapply 执行完全相同的操作,但保留原始索引并且不会折叠。”请考虑以下事项。

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 列中有非零条目的ids。

>>> 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 函数中发生的事情的任何提示。干杯。

【问题讨论】:

  • apply 不会折叠数据。 apply 很灵活,可以返回任意大小的系列或数据帧。 transform 始终保留每个组的行数。 transform 还将每个单独的列作为一个系列发送给调用函数。 apply 将整个数据帧发送给调用函数。
  • 啊哈!谢谢@piRSquared。在阅读该评论并查看源代码后,我想我更好地理解了为什么会发生这种情况。

标签: python pandas transform apply


【解决方案1】:

我发现它更明确,只需添加另一个带有 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 对象时,我看不出任何区别。

【讨论】:

    【解决方案2】:

    看起来 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
    

    【讨论】:

      猜你喜欢
      • 2018-12-07
      • 1970-01-01
      • 2017-03-12
      • 2019-04-12
      • 1970-01-01
      • 2019-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多