Pandas按数字分组并查找低于当前日期的日期

k4ymrczo  于 2023-06-28  发布在  其他
关注(0)|答案(4)|浏览(148)

我有一个pandas数据框,里面有id,number和date。我想创建一个新的列,显示有多少日期低于当前ID的日期相同的数字(按数字分组)。

import pandas as pd
df = pd.DataFrame({'id': [1,2,3,4,5,6],'number':['a', 'a', 'a', 'a', 'b', 'c'], 'date' : ['2023-06-20', '2022-06-20', '2021-06-20', '2021-07-20', '2022-06-20', '2023-06-20']})
print(df)

  id number        date
0   1      a  2023-06-20
1   2      a  2022-06-20
2   3      a  2021-06-20
3   4      a  2021-07-20
4   5      b  2022-06-20
5   6      c  2023-06-20

我使用了pandas apply函数进行过滤。问题是我有300k+行,在代码下面运行大约需要2个小时。如何优化它?

df['result'] = df.apply(lambda x:len(df[(df['number'] == x['number']) & (df['date'] < x['date'])]), axis = 1)
print(df)
 id number        date    result
0   1      a  2023-06-20     3
1   2      a  2022-06-20     2
2   3      a  2021-06-20     0
3   4      a  2021-07-20     1
4   5      b  2022-06-20     0
5   6      c  2023-06-20     0
tyg4sfes

tyg4sfes1#

您可以按date对 Dataframe 进行排序,然后计算每个组的累积计数:

df['result'] = df.sort_values('date').groupby('number').cumcount()
print(df)

# Output
   id number        date  result
0   1      a  2023-06-20       3
1   2      a  2022-06-20       2
2   3      a  2021-06-20       0
3   4      a  2021-07-20       1
4   5      b  2022-06-20       0
5   6      c  2023-06-20       0

注意:它之所以有效,是因为date在你的 Dataframe 中是唯一的。

2izufjch

2izufjch2#

您可以优化代码以更有效地计算所需的结果。您可以利用pandas groupbycumcount函数的强大功能,而不是使用apply函数。这些函数允许您执行所需的计算,而无需嵌套循环。
下面是更新的代码:

import pandas as pd

# Create the DataFrame
df = pd.DataFrame({'id': [1, 2, 3, 4, 5, 6],
                   'number': ['a', 'a', 'a', 'a', 'b', 'c'],
                   'date': ['2023-06-20', '2022-06-20', '2021-06-20', '2021-07-20', '2022-06-20', '2023-06-20']})

# Calculate the result using groupby and cumcount
df['result'] = df.groupby('number')['date'].cumcount()

# Print the resulting DataFrame
print(df)

参考文献:
grouby上的Pandas文档cumcount上的Pandas文档

vawmfj5a

vawmfj5a3#

正如其他答案中所指出的,如果你的日期是唯一的,那么在排序值上使用简单的groupby.cumcount就可以了。
如果你可以有重复的结果将是不正确的,计算变得更加复杂。
然后,您需要计算每个日期/id的出现次数,然后计算这些值的cumsum

tmp = (df.sort_values(by=['number', 'date'], ascending=[True, False])
   .groupby(['date', 'number'], as_index=False).size()
   .assign(n=lambda d: d.groupby('number')['size'].transform(lambda x: x.cumsum().shift(fill_value=0)))
 )

df['result'] = df.merge(tmp, on=['date', 'number'], how='left')['n']
                   
 
   id number        date  result
0   1      a  2023-06-20       3
1   2      a  2022-06-20       2
2   3      a  2021-06-20       0
3   4      a  2021-07-20       1
4   5      b  2022-06-20       0
5   6      c  2023-06-20       0

日期重复时的差异示例:

id number        date  result  cumcount
0   0      a  2022-06-20       2         2
1   1      a  2023-06-20       4         4
2   2      a  2022-06-20       2         3
3   3      a  2021-06-20       0         0
4   4      a  2021-07-20       1         1
5   5      b  2022-06-20       0         0
6   6      c  2023-06-20       0         0
gajydyqb

gajydyqb4#

下面是使用rank()的选项

df['result'] = df.groupby('number')['date'].rank(method = 'min').sub(1).astype(int)

输出:

id number       date  result
0   1      a 2023-06-20       3
1   2      a 2022-06-20       2
2   3      a 2021-06-20       0
3   4      a 2021-07-20       1
4   5      b 2022-06-20       0
5   6      c 2023-06-20       0

相关问题