3 回答
TA贡献1785条经验 获得超8个赞
我同样感到困惑.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从两列中获取值,而“it”实际上并不同时“查看”这两个列(可以这么说)。transform将逐一查看dataframe列,并返回由重复的标量组成的序列(或序列组)。len(input_column)时代。
所以这个标量,应该被.transform使Series是对输入应用某种约简函数的结果。Series(一次只能在一个系列/列上)。
请考虑这个示例(在您的dataframe上):
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))将以完全相同的方式工作,但如果您尝试在dataframe上使用它,则会失败:
df.groupby('A').apply(zscore)
给出错误:
ValueError: operands could not be broadcast together with shapes (6,) (2,)
所以还有别的地方.transform有用吗?最简单的情况是尝试将约简函数的结果分配回原始数据。
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
我希望这能增加一点清晰度。
TA贡献1966条经验 获得超4个赞
两大区别apply和transform
之间有两个主要的区别。transform和apply群方法
apply隐式地将每个组的所有列作为DataFrame到自定义函数,同时transform将每个组的每一列作为系列到自定义函数
传递给apply可以返回标量、系列或DataFrame(或numpy数组甚至列表)。传递给transform必须返回与组相同长度的序列(一维序列、数组或列表)。
所以,transform一次只做一个系列的作品apply同时处理整个DataFrame。
检查自定义函数
检查传递给您的自定义函数的输入会有很大帮助。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
现在让我们把这个函数传递给groupbyapply和transform方法来查看传递给它的对象:
df.groupby('State').apply(inspect)
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
RuntimeError
如您所见,DataFrame被传递到inspect功能。您可能想知道为什么类型DataFrame被打印了两次。第一组熊猫跑两次。它这样做是为了确定是否有一种快速的方法来完成计算。这是一个你不应该担心的小细节。
现在,让我们做同样的事情transform
df.groupby('State').transform(inspect)
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
RuntimeError
它被传递了一个系列-一个完全不同的熊猫对象。
所以,transform一次只能使用一个系列。它不可能同时对两列采取行动。所以,如果我们尝试减去列a从…b在我们的自定义函数中,我们将得到一个错误transform..见下文:
def subtract_two(x):
return x['a'] - x['b']
df.groupby('State').transform(subtract_two)
KeyError: ('a', 'occurred at index a')
当熊猫试图找到系列索引时,我们得到了一个KeyErrora并不存在。您可以用apply因为它拥有整个DataFrame:
df.groupby('State').apply(subtract_two)
State
Florida 2 -2
3 -8
Texas 0 -2
1 -5
dtype: int64
输出是一个Series,由于保留了原始索引,所以有点混乱,但是我们可以访问所有列。
显示传递的熊猫对象
它可以帮助更多地显示整个熊猫对象的自定义功能,这样你就可以准确地看到你在操作什么。你可以用print语句,我喜欢使用display函数的IPython.display模块,以便在jupyter笔记本中以HTML格式很好地输出DataFrame:
from IPython.display import display
def subtract_two(x):
display(x)
return x['a'] - x['b']
截图:enter image description here
转换必须返回与组大小相同的一维序列。
另一个区别是transform必须返回与组大小相同的单维度序列。在这个特定的实例中,每个组有两行,因此transform必须返回两行的序列。如果没有,则会引发错误:
def return_three(x):
return np.array([1, 2, 3])
df.groupby('State').transform(return_three)
ValueError: transform must return a scalar value for each group
错误消息并不真正描述问题。必须返回与组长度相同的序列。所以,像这样的函数会起作用:
def rand_group_len(x):
return np.random.rand(len(x))
df.groupby('State').transform(rand_group_len)
a b
0 0.962070 0.151440
1 0.440956 0.782176
2 0.642218 0.483257
3 0.056047 0.238208
返回单个标量对象也适用于transform
如果您只从自定义函数返回一个标量,那么transform将用于组中的每一行:
def group_sum(x):
return x.sum()
df.groupby('State').transform(group_sum)
a b
0 9 16
1 9 16
2 4 14
3 4 14
TA贡献1853条经验 获得超9个赞
我将用一个非常简单的片段来说明两者之间的区别:
test = pd.DataFrame({'id':[1,2,3,1,2,3,1,2,3], 'price':[1,2,3,2,3,1,3,1,2]})
grouping = test.groupby('id')['price']
DataFrame如下所示:
id price
0 1 1
1 2 2
2 3 3
3 1 2
4 2 3
5 3 1
6 1 3
7 2 1
8 3 2
本表中有3个客户ID,每个客户进行了三次交易,每次支付1,2,3美元。
现在,我想找到每个客户的最低付款。有两种方法:
使用apply:
Grouping.min()
回报如下:
id
1 1
2 1
3 1
Name: price, dtype: int64
pandas.core.series.Series # return type
Int64Index([1, 2, 3], dtype='int64', name='id') #The returned Series' index
# lenght is 3
使用transform:
分组变换(MIN)
回报如下:
0 1
1 1
2 1
3 1
4 1
5 1
6 1
7 1
8 1
Name: price, dtype: int64
pandas.core.series.Series # return type
RangeIndex(start=0, stop=9, step=1) # The returned Series' index
# length is 9
两个方法都返回一个Series对象,但是length第一个是3,而length第二个是9。
如果你想回答What is the minimum price paid by each customer,然后apply方法是比较适合选择的方法。
如果你想回答What is the difference between the amount paid for each transaction vs the minimum payment,然后你想用transform,因为:
test['minimum'] = grouping.transform(min) # ceates an extra column filled with minimum payment
test.price - test.minimum # returns the difference for each row
Apply在这里工作并不仅仅是因为它返回一个3大小的系列,但是原始df的长度是9,您不能轻松地将它集成回原始df。
添加回答
举报