3 回答

TA貢獻1880條經驗 獲得超4個贊
我同樣感到困惑.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上使用它,則會失?。?/p>
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貢獻1829條經驗 獲得超7個贊
兩大區別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貢獻1779條經驗 獲得超6個贊
我將用一個非常簡單的片段來說明兩者之間的區別:
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。
添加回答
舉報