【发布时间】:2016-05-12 12:02:15
【问题描述】:
我的数据看起来像这样
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 行也是不同的组。
看待这个问题的一种稍微不同的方式是,我想像我在这里一样进行分组,删除日期列(这对于最初形成组很重要),然后在我删除后在相等的组之间聚合日期。
【问题讨论】:
-
现在
'UID'对行0和1是如何相同的?'ID1'两行相同,但'ID2'和'Price'实际上是不同的。 -
好问题。我应该解释得更好。 ID1 就像 ID2 的父 ID。因此,第 0 行和第 1 行是同一组的一部分:该组由 ID1 = 11 及其当天的所有子项(ID2)组成。我需要该组级别的唯一 ID。这些行的 UID 与最后两行相同,尽管日期不同,因为 ID1、ID2 和价格相同。
-
唯一标识符必须能够识别任何行,因此您可以命名列,其组合可以保证行的唯一性或使用人工唯一键,如 GUID。否则迟早你的唯一密钥算法会出现问题。只是我的 0.02 美元。
-
感谢您的 cmets MaxU。我认为我当前的方法确实可以识别任何行。如果我删除存在的排名调用只是为了使最终结果更漂亮,则 1 的 UID 实际上是“11210010.99220011.99”。从中我可以准确读出它对应的行:ID1 = 11,ID2 = 21,Price = 10.99;然后该组中的下一行 ID2 = 22,依此类推。很难方便地命名列,因为组的大小不同。抱歉,我很难解释清楚。
-
您的数据中的第 0、3 和 5 行有什么区别? (为什么 0 和 5 有相同的“UID”,而不是 3?或者它是一个错字?)