[英]Groupby in python pandas: Fast Way
我想改善 python pandas 中groupby
的時間。 我有這個代碼:
df["Nbcontrats"] = df.groupby(['Client', 'Month'])['Contrat'].transform(len)
目標是計算客戶在一個月內擁有多少合同,並將此信息添加到新列 ( Nbcontrats
) 中。
Client
:客戶端代碼Month
: 數據提取月份Contrat
:合同號我想改善時間。 下面我只使用我的真實數據的一個子集:
%timeit df["Nbcontrats"] = df.groupby(['Client', 'Month'])['Contrat'].transform(len)
1 loops, best of 3: 391 ms per loop
df.shape
Out[309]: (7464, 61)
如何提高執行時間?
這是繼續的一種方法:
將輸入數據幀中的相關列( ['Client', 'Month']
)切出到 NumPy 數組中。 這主要是一個以性能為中心的想法,因為我們稍后將使用 NumPy 函數,這些函數經過優化以與 NumPy 數組一起使用。
將['Client', 'Month']
的兩列數據轉換為單個1D
數組,這將是線性索引等價物,將兩列中的元素視為對。 因此,我們可以假設來自'Client'
的元素代表行索引,而'Month'
元素是列索引。 這就像從2D
到1D
。 但是,問題將是決定 2D 網格的形狀來執行這樣的映射。 為了涵蓋所有對,一個安全的假設是假設一個二維網格,由於 Python 中的基於 0 的索引,其維度比沿每列的最大值多 1。 因此,我們將得到線性指數。
接下來,我們根據每個線性索引的唯一性來標記它們。 我認為這將對應於使用grouby
獲得的密鑰。 我們還需要沿該一維數組的整個長度獲取每個組/唯一鍵的計數。 最后,使用這些標簽對計數進行索引應該為每個元素映射相應的計數。
這就是它的全部想法! 這是實現 -
# Save relevant columns as a NumPy array for performing NumPy operations afterwards
arr_slice = df[['Client', 'Month']].values
# Get linear indices equivalent of those columns
lidx = np.ravel_multi_index(arr_slice.T,arr_slice.max(0)+1)
# Get unique IDs corresponding to each linear index (i.e. group) and grouped counts
unq,unqtags,counts = np.unique(lidx,return_inverse=True,return_counts=True)
# Index counts with the unique tags to map across all elements with the counts
df["Nbcontrats"] = counts[unqtags]
運行時測試
1) 定義函數:
def original_app(df):
df["Nbcontrats"] = df.groupby(['Client', 'Month'])['Contrat'].transform(len)
def vectorized_app(df):
arr_slice = df[['Client', 'Month']].values
lidx = np.ravel_multi_index(arr_slice.T,arr_slice.max(0)+1)
unq,unqtags,counts = np.unique(lidx,return_inverse=True,return_counts=True)
df["Nbcontrats"] = counts[unqtags]
2) 驗證結果:
In [143]: # Let's create a dataframe with 100 unique IDs and of length 10000
...: arr = np.random.randint(0,100,(10000,3))
...: df = pd.DataFrame(arr,columns=['Client','Month','Contrat'])
...: df1 = df.copy()
...:
...: # Run the function on the inputs
...: original_app(df)
...: vectorized_app(df1)
...:
In [144]: np.allclose(df["Nbcontrats"],df1["Nbcontrats"])
Out[144]: True
3)最后計時:
In [145]: # Let's create a dataframe with 100 unique IDs and of length 10000
...: arr = np.random.randint(0,100,(10000,3))
...: df = pd.DataFrame(arr,columns=['Client','Month','Contrat'])
...: df1 = df.copy()
...:
In [146]: %timeit original_app(df)
1 loops, best of 3: 645 ms per loop
In [147]: %timeit vectorized_app(df1)
100 loops, best of 3: 2.62 ms per loop
使用DataFrameGroupBy.size
方法:
df.set_index(['Client', 'Month'], inplace=True)
df['Nbcontrats'] = df.groupby(level=(0,1)).size()
df.reset_index(inplace=True)
大多數工作是將結果分配回源 DataFrame 的列中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.