簡體   English   中英

Python pandas:為組創建唯一標識符的快捷方式

[英]Python pandas:Fast way to create a unique identifier for groups

我的數據看起來像這樣

df
Out[10]: 
  ID1 ID2  Price       Date
0  11  21  10.99  3/15/2016
1  11  22  11.99  3/15/2016
2  12  23      5  3/15/2016
3  11  21  10.99  3/16/2016
4  11  22  12.99  3/16/2016
5  11  21  10.99  3/17/2016
6  11  22  11.99  3/17/2016

目標是為每個ID1組獲取一個唯一的ID,並為每個ID2提供特定的價格,如下所示:

    # Desired Result
df
Out[14]: 
  ID1 ID2  Price       Date  UID
0  11  21  10.99  3/15/2016    1
1  11  22  11.99  3/15/2016    1
2  12  23      5  3/15/2016    7
3  11  21  10.99  3/16/2016    5
4  11  22  12.99  3/16/2016    5
5  11  21  10.99  3/17/2016    1
6  11  22  11.99  3/17/2016    1

由於數據的大小,速度是一個問題。 我能想到的最好的方法是在下面,但它仍然比想要的慢很多。 如果有人有一種他們認為應該自然更快的方式,我很樂意聽到它。 或者也許有一種簡單的方法可以並行地進行組內操作以加快速度?

我的方法基本上連接ID和價格(用零填充以確保相同的長度),然后采用排名來簡化最終的ID。 瓶頸是使用.transform(np.sum)完成的組內連接。

# concatenate ID2 and Price
df['ID23'] = df['ID2'] + df['Price']

df
Out[12]: 
  ID1 ID2  Price       Date     ID23
0  11  21  10.99  3/15/2016  2110.99
1  11  22  11.99  3/15/2016  2211.99
2  12  23      5  3/15/2016      235
3  11  21  10.99  3/16/2016  2110.99
4  11  22  12.99  3/16/2016  2212.99
5  11  21  10.99  3/17/2016  2110.99
6  11  22  11.99  3/17/2016  2211.99


# groupby ID1 and Date and then concatenate the ID23's
grouped = df.groupby(['ID1','Date'])
df['summed'] = grouped['ID23'].transform(np.sum)

df
Out[16]: 
  ID1 ID2    Price       Date      ID23            summed                UID
0   6   3  0010.99  3/15/2016  30010.99  30010.9960011.99  630010.9960011.99
1   6   6  0011.99  3/15/2016  60011.99  30010.9960011.99  630010.9960011.99
2   7   7  0000005  3/15/2016  70000005          70000005          770000005
3   6   3  0010.99  3/16/2016  30010.99  30010.9960012.99  630010.9960012.99
4   6   6  0012.99  3/16/2016  60012.99  30010.9960012.99  630010.9960012.99
5   6   3  0010.99  3/17/2016  30010.99  30010.9960011.99  630010.9960011.99
6   6   6  0011.99  3/17/2016  60011.99  30010.9960011.99  630010.9960011.99

# Concatenate ID1 on the front and take rank to get simpler ID's    
df['UID'] = df['ID1'] + df['summed'] 
df['UID'] = df['UID'].rank(method = 'min')

# Drop unnecessary columns
df.drop(['ID23','summed'], axis=1, inplace=True)

更新:

為了澄清,請考慮原始數據分組如下:

grouped = df.groupby(['ID1','Date'])
    for name, group in grouped:
    print group

  ID1 ID2  Price       Date
0  11  21  10.99  3/15/2016
1  11  22  11.99  3/15/2016

  ID1 ID2  Price       Date
3  11  21  10.99  3/16/2016
4  11  22  12.99  3/16/2016

  ID1 ID2  Price       Date
5  11  21  10.99  3/17/2016
6  11  22  11.99  3/17/2016

  ID1 ID2 Price       Date
2  12  23     5  3/15/2016

UID應該在組級別並且如果關於該組的所有內容相同而忽略日期,則匹配。 因此,在這種情況下,第一個和第三個打印組是相同的,這意味着行0,1,5和6應該都獲得相同的UID。 第3行和第4行屬於不同的組,因為價格已更改,因此需要不同的UID。 第2行也是一個不同的組。

看待這個問題的一種略微不同的方式是,我想按照我的方式進行分組,刪除日期列(這對於最初形成組很重要),然后在刪除日期后對各組進行匯總。

編輯:下面的代碼實際上比OP的解決方案慢。 我現在離開它,以防萬一有人用它來寫一個更好的解決方案。


對於可視化,我將使用以下數據:

df
Out[421]: 
    ID1  ID2  Price       Date
0    11   21  10.99  3/15/2016
1    11   22  11.99  3/15/2016
2    12   23   5.00  3/15/2016
3    11   21  10.99  3/16/2016
4    11   22  12.99  3/16/2016
5    11   21  10.99  3/17/2016
6    11   22  11.99  3/17/2016
7    11   22  11.99  3/18/2016
8    11   21  10.99  3/18/2016
9    12   22  11.99  3/18/2016
10   12   21  10.99  3/18/2016
11   12   23   5.00  3/19/2016
12   12   23   5.00  3/19/2016

首先,讓我們按“ID1”和“日期”對其進行分組,並將結果聚合為元組(已排序)。 我還重置了索引,因此有一個名為'index'的新列。

gr = df.reset_index().groupby(['ID1','Date'], as_index = False)
df1 = gr.agg(lambda x : tuple(sorted(x)))
df1
Out[425]: 
   ID1       Date     index       ID2           Price
0   11  3/15/2016    (0, 1)  (21, 22)  (10.99, 11.99)
1   11  3/16/2016    (3, 4)  (21, 22)  (10.99, 12.99)
2   11  3/17/2016    (5, 6)  (21, 22)  (10.99, 11.99)
3   11  3/18/2016    (7, 8)  (21, 22)  (10.99, 11.99)
4   12  3/15/2016      (2,)     (23,)          (5.0,)
5   12  3/18/2016   (9, 10)  (21, 22)  (10.99, 11.99)
6   12  3/19/2016  (11, 12)  (23, 23)      (5.0, 5.0)

完成所有分組后,我將使用列'index'來訪問df行(它們最好是唯一的)。 (另請注意, df1.indexdf1['index']是完全不同的東西。)

現在,讓我們分組'index' (跳過日期):

df2 = df1.groupby(['ID1','ID2','Price'], as_index = False)['index'].sum()
df2
Out[427]: 
   ID1       ID2           Price               index
0   11  (21, 22)  (10.99, 11.99)  (0, 1, 5, 6, 7, 8)
1   11  (21, 22)  (10.99, 12.99)              (3, 4)
2   12  (21, 22)  (10.99, 11.99)             (9, 10)
3   12     (23,)          (5.0,)                (2,)
4   12  (23, 23)      (5.0, 5.0)            (11, 12)

我相信這是問題所需的分組,因此我們現在可以為df添加標簽。 例如這樣:

df['GID'] = -1
for i, t in enumerate(df2['index']):
    df.loc[t,'GID'] = i

df
Out[430]: 
    ID1  ID2  Price       Date  GID
0    11   21  10.99  3/15/2016    0
1    11   22  11.99  3/15/2016    0
2    12   23   5.00  3/15/2016    3
3    11   21  10.99  3/16/2016    1
4    11   22  12.99  3/16/2016    1
5    11   21  10.99  3/17/2016    0
6    11   22  11.99  3/17/2016    0
7    11   22  11.99  3/18/2016    0
8    11   21  10.99  3/18/2016    0
9    12   22  11.99  3/18/2016    2
10   12   21  10.99  3/18/2016    2
11   12   23   5.00  3/19/2016    4
12   12   23   5.00  3/19/2016    4

或者以一種可能更快但更棘手的方式:

# EXPERIMENTAL CODE!
df3 = df2['index'].apply(pd.Series).stack().reset_index()
df3.index = df3[0].astype(int)
df['GID'] = df3['level_0']

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM