我有一个包含ID列,日期列和值的数据集。我想计算连续日期范围内id的连续出现/重复值。
我的问题与Count consecutive duplicate values by group非常相似,但使用Python。 此外,问题与How to find duplicates in pandas dataframe不同,因为我需要计数基于两列,其中一列不相同-它是日期(它会更改,但如果是连续的,我想对其进行计数)
这是一个示例数据集:
xx.cpp
我希望结果数据集为:
xx.cpp
我用0而不是1标记了“单个”,因为我需要将两者分开。我将处理批处理的“重复项”与单记录不同。
谢谢!
答案 0 :(得分:5)
示例:
df = pd.DataFrame({'ID': [79, 79, 79, 79, 79, 79, 80, 80, 80, 80, 80, 80, 80],
'tDate': [pd.Timestamp('2019-07-12 00:00:00'),
pd.Timestamp('2019-07-13 00:00:00'),
pd.Timestamp('2019-07-18 00:00:00'),
pd.Timestamp('2019-07-19 00:00:00'),
pd.Timestamp('2019-07-20 00:00:00'),
pd.Timestamp('2019-08-03 00:00:00'),
pd.Timestamp('2019-06-21 00:00:00'),
pd.Timestamp('2019-06-22 00:00:00'),
pd.Timestamp('2019-07-18 00:00:00'),
pd.Timestamp('2019-07-19 00:00:00'),
pd.Timestamp('2019-07-26 00:00:00'),
pd.Timestamp('2019-08-02 00:00:00'),
pd.Timestamp('2019-08-03 00:00:00')],
'value':[397, 404, 405, 406, 408, 413, 397, 404, 405, 406, 408, 410, 413]})
print (df)
ID tDate value
0 79 2019-07-12 397
1 79 2019-07-13 404
2 79 2019-07-18 405
3 79 2019-07-19 406
4 79 2019-07-20 408
5 79 2019-08-03 413
6 80 2019-06-21 397
7 80 2019-06-22 404
8 80 2019-07-18 405
9 80 2019-07-19 406
10 80 2019-07-26 408
11 80 2019-08-02 410
12 80 2019-08-03 413
解决方案:
a = df.groupby('ID')['tDate'].diff().eq(pd.Timedelta(1, unit='d'))
s = (~a).cumsum()
df['consec_count']=np.where(a.groupby(s).transform('any'), df.groupby(s).cumcount(1).add(1),0)
print (df)
ID tDate value consec_count
0 79 2019-07-12 397 1
1 79 2019-07-13 404 2
2 79 2019-07-18 405 1
3 79 2019-07-19 406 2
4 79 2019-07-20 408 3
5 79 2019-08-03 413 0
6 80 2019-06-21 397 1
7 80 2019-06-22 404 2
8 80 2019-07-18 405 1
9 80 2019-07-19 406 2
10 80 2019-07-26 408 0
11 80 2019-08-02 410 1
12 80 2019-08-03 413 2
说明:
首先创建一个遮罩,用DataFrameGroupBy.diff
比较一天中每组的差异:
print (df.assign(diff= df.groupby('ID')['tDate'].diff(),
a = df.groupby('ID')['tDate'].diff().eq(pd.Timedelta(1, unit='d'))))
ID tDate value diff a
0 79 2019-07-12 397 NaT False
1 79 2019-07-13 404 1 days True
2 79 2019-07-18 405 5 days False
3 79 2019-07-19 406 1 days True
4 79 2019-07-20 408 1 days True
5 79 2019-08-03 413 14 days False
6 80 2019-06-21 397 NaT False
7 80 2019-06-22 404 1 days True
8 80 2019-07-18 405 26 days False
9 80 2019-07-19 406 1 days True
10 80 2019-07-26 408 7 days False
11 80 2019-08-02 410 7 days False
12 80 2019-08-03 413 1 days True
通过Series.cumsum
创建唯一组,并使用~
反转条件:
print (df.assign(diff= df.groupby('ID')['tDate'].diff(),
a = df.groupby('ID')['tDate'].diff().eq(pd.Timedelta(1, unit='d')),
a_neg = ~a,
s = (~a).cumsum()))
ID tDate value diff a a_neg s
0 79 2019-07-12 397 NaT False True 1
1 79 2019-07-13 404 1 days True False 1
2 79 2019-07-18 405 5 days False True 2
3 79 2019-07-19 406 1 days True False 2
4 79 2019-07-20 408 1 days True False 2
5 79 2019-08-03 413 14 days False True 3
6 80 2019-06-21 397 NaT False True 4
7 80 2019-06-22 404 1 days True False 4
8 80 2019-07-18 405 26 days False True 5
9 80 2019-07-19 406 1 days True False 5
10 80 2019-07-26 408 7 days False True 6
11 80 2019-08-02 410 7 days False True 7
12 80 2019-08-03 413 1 days True False 7
用GroupBy.transform
和DataFrameGroupBy.any
创建掩码,以测试每个组是否至少包含一个True
-然后将组的所有值设置为True
s:
print (df.assign(diff= df.groupby('ID')['tDate'].diff(),
a = df.groupby('ID')['tDate'].diff().eq(pd.Timedelta(1, unit='d')),
a_neg = ~a,
s = (~a).cumsum(),
mask = a.groupby(s).transform('any')))
ID tDate value consec_count diff a a_neg s mask
0 79 2019-07-12 397 1 NaT False True 1 True
1 79 2019-07-13 404 2 1 days True False 1 True
2 79 2019-07-18 405 1 5 days False True 2 True
3 79 2019-07-19 406 2 1 days True False 2 True
4 79 2019-07-20 408 3 1 days True False 2 True
5 79 2019-08-03 413 0 14 days False True 3 False
6 80 2019-06-21 397 1 NaT False True 4 True
7 80 2019-06-22 404 2 1 days True False 4 True
8 80 2019-07-18 405 1 26 days False True 5 True
9 80 2019-07-19 406 2 1 days True False 5 True
10 80 2019-07-26 408 0 7 days False True 6 False
11 80 2019-08-02 410 1 7 days False True 7 True
12 80 2019-08-03 413 2 1 days True False 7 True
按GroupBy.cumcount
按组s
创建计数器:
print (df.assign(diff= df.groupby('ID')['tDate'].diff(),
a = df.groupby('ID')['tDate'].diff().eq(pd.Timedelta(1, unit='d')),
a_neg = ~a,
s = (~a).cumsum(),
mask = a.groupby(s).transform('any'),
c = df.groupby(s).cumcount(1).add(1)))
ID tDate value consec_count diff a a_neg s mask c
0 79 2019-07-12 397 1 NaT False True 1 True 1
1 79 2019-07-13 404 2 1 days True False 1 True 2
2 79 2019-07-18 405 1 5 days False True 2 True 1
3 79 2019-07-19 406 2 1 days True False 2 True 2
4 79 2019-07-20 408 3 1 days True False 2 True 3
5 79 2019-08-03 413 0 14 days False True 3 False 1
6 80 2019-06-21 397 1 NaT False True 4 True 1
7 80 2019-06-22 404 2 1 days True False 4 True 2
8 80 2019-07-18 405 1 26 days False True 5 True 1
9 80 2019-07-19 406 2 1 days True False 5 True 2
10 80 2019-07-26 408 0 7 days False True 6 False 1
11 80 2019-08-02 410 1 7 days False True 7 True 1
12 80 2019-08-03 413 2 1 days True False 7 True 2
最后将numpy.where
的0
和https://docs.halium.org/en/latest/porting/get-sources.html加上掩码mask
:
print (df.assign(diff= df.groupby('ID')['tDate'].diff(),
a = df.groupby('ID')['tDate'].diff().eq(pd.Timedelta(1, unit='d')),
a_neg = ~a,
s = (~a).cumsum(),
mask = a.groupby(s).transform('any'),
c = df.groupby(s).cumcount(1).add(1),
out = np.where(mask, df.groupby(s).cumcount(1).add(1), 0)))
ID tDate value consec_count diff a a_neg s mask c out
0 79 2019-07-12 397 1 NaT False True 1 True 1 1
1 79 2019-07-13 404 2 1 days True False 1 True 2 2
2 79 2019-07-18 405 1 5 days False True 2 True 1 1
3 79 2019-07-19 406 2 1 days True False 2 True 2 2
4 79 2019-07-20 408 3 1 days True False 2 True 3 3
5 79 2019-08-03 413 0 14 days False True 3 False 1 0
6 80 2019-06-21 397 1 NaT False True 4 True 1 1
7 80 2019-06-22 404 2 1 days True False 4 True 2 2
8 80 2019-07-18 405 1 26 days False True 5 True 1 1
9 80 2019-07-19 406 2 1 days True False 5 True 2 2
10 80 2019-07-26 408 0 7 days False True 6 False 1 0
11 80 2019-08-02 410 1 7 days False True 7 True 1 1
12 80 2019-08-03 413 2 1 days True False 7 True 2 2
答案 1 :(得分:1)
您也可以尝试在ID
和or
的groupby上创建掩码,并用shift(-1)
标记所有连续的行True
并分配给掩码s1
。最后,在np.where
和s1
上使用s1.groupby.cumsum
s = df.groupby('ID').tDate.diff().eq(pd.Timedelta(days=1))
s1 = s | s.shift(-1, fill_value=False)
df['consec_count'] = np.where(s1, s1.groupby(df.ID).cumsum(), 0)
Out[185]:
ID tDate value consec_count
0 79 2019-06-21 397 0
1 79 2019-07-13 404 0
2 79 2019-07-18 405 1
3 79 2019-07-19 406 2
4 79 2019-08-02 410 0
5 79 2019-08-09 413 0