如何移动 pandas 列元素以跨时间匹配观察值?
How to shift pandas column elements for matching observations across time?
假设我们有以下数据框:
Date Type Country Value
0 2016-04-30 A NL 1
1 2016-04-30 A BE 2
2 2016-04-30 B NL 3
3 2016-04-30 B BE 4
4 2016-04-30 C NL 5
5 2016-04-30 C BE 6
6 2016-04-30 C FR 7
7 2016-04-30 C UK 8
8 2016-05-31 A NL 9
9 2016-05-31 A BE 10
10 2016-05-31 A FR 11
11 2016-05-31 B NL 12
12 2016-05-31 B BE 13
13 2016-05-31 B FR 14
14 2016-05-31 C NL 15
15 2016-05-31 C BE 16
16 2016-05-31 C UK 17
17 2016-05-31 C SL 18
18 2016-06-30 A NL 19
19 2016-06-30 B FR 20
20 2016-06-30 B UK 21
21 2016-06-30 B SL 22
22 2016-06-30 C NL 23
23 2016-06-30 C BE 24
可以用下面的代码计算:
df = pd.DataFrame([['2016-04-30','A','NL',1], ['2016-04-30','A', "BE" ,2], ['2016-04-30', 'B', 'NL',3], ['2016-04-30','B','BE',4], ['2016-04-30','C','NL',5], ['2016-04-30','C','BE',6],['2016-04-30','C','FR', 7], ['2016-04-30','C','UK',8], ['2016-05-31','A','NL',9], ['2016-05-31','A','BE',10], ['2016-05-31','A','FR',11], ['2016-05-31','B','NL',12], ['2016-05-31','B','BE',13], ['2016-05-31','B','FR',14], ['2016-05-31','C','NL',15], ['2016-05-31','C','BE',16], ['2016-05-31','C','UK',17], ['2016-05-31','C','SL',18], ['2016-06-30','A','NL',19], ['2016-06-30','B','FR',20], ['2016-06-30','B','UK',21], ['2016-06-30','B','SL',22], ['2016-06-30','C','NL',23], ['2016-06-30','C','BE',24]], columns=['Date','Type' ,'Country' ,'Value'])
我想添加一个额外的列 'ValueShifted',它基本上会随着时间的推移改变观察结果。因此,例如对于观察值 'Date: 2016-05-31, Type: B, Country: BE',我想将 'ValueShifted' 设置为 4。如果观察值在前一时期不可用,我想将其设置为 NaN。
我可以用蛮力完成,但这对我的实际数据集来说会花费太多时间。有没有办法有效地做到这一点?
预期 df:
Date Type Country Value ValueShifted
0 2016-04-30 A NL 1 nan
1 2016-04-30 A BE 2 nan
2 2016-04-30 B NL 3 nan
3 2016-04-30 B BE 4 nan
4 2016-04-30 C NL 5 nan
5 2016-04-30 C BE 6 nan
6 2016-04-30 C FR 7 nan
7 2016-04-30 C UK 8 nan
8 2016-05-31 A NL 9 1
9 2016-05-31 A BE 10 2
10 2016-05-31 A FR 11 nan
11 2016-05-31 B NL 12 3
12 2016-05-31 B BE 13 4
13 2016-05-31 B FR 14 nan
14 2016-05-31 C NL 15 5
15 2016-05-31 C BE 16 6
16 2016-05-31 C UK 17 8
17 2016-05-31 C SL 18 nan
18 2016-06-30 A NL 19 9
19 2016-06-30 B FR 20 14
20 2016-06-30 B UK 21 nan
21 2016-06-30 B SL 22 nan
22 2016-06-30 C NL 23 15
23 2016-06-30 C BE 24 16
IIUC,你想要GroupBy.shift
:
#df['Date']=pd.to_datetime(df['Date'])
#df=df.sort_values(['Date','Type']) #order if necessary
df['ValueShifted']=df.groupby(['Type','Country'])['Value'].shift()
print(df)
输出
Date Type Country Value ValueShifted
0 2016-04-30 A NL 1 NaN
1 2016-04-30 A BE 2 NaN
2 2016-04-30 B NL 3 NaN
3 2016-04-30 B BE 4 NaN
4 2016-04-30 C NL 5 NaN
5 2016-04-30 C BE 6 NaN
6 2016-04-30 C FR 7 NaN
7 2016-04-30 C UK 8 NaN
8 2016-05-31 A NL 9 1.0
9 2016-05-31 A BE 10 2.0
10 2016-05-31 A FR 11 NaN
11 2016-05-31 B NL 12 3.0
12 2016-05-31 B BE 13 4.0
13 2016-05-31 B FR 14 NaN
14 2016-05-31 C NL 15 5.0
15 2016-05-31 C BE 16 6.0
16 2016-05-31 C UK 17 8.0
17 2016-05-31 C SL 18 NaN
18 2016-06-30 A NL 19 9.0
19 2016-06-30 B FR 20 14.0
20 2016-06-30 B UK 21 NaN
21 2016-06-30 B SL 22 NaN
22 2016-06-30 C NL 23 15.0
23 2016-06-30 C BE 24 16.0
如果存在遗漏观察的可能性,最安全的方法是复制DataFrame,手动更改日期,然后才能精确合并。
df['Date'] = pd.to_datetime(df.Date)
df2 = df.copy()
df2['Date'] = df2['Date'] + pd.offsets.MonthEnd(1)
df2 = df2.rename(columns={'Value': 'ValueShifted'})
df = df.merge(df2, on=['Date', 'Type', 'Country'], how='left')
Date Type Country Value ValueShifted
0 2016-04-30 A NL 1 NaN
1 2016-04-30 A BE 2 NaN
2 2016-04-30 B NL 3 NaN
3 2016-04-30 B BE 4 NaN
4 2016-04-30 C NL 5 NaN
5 2016-04-30 C BE 6 NaN
6 2016-04-30 C FR 7 NaN
7 2016-04-30 C UK 8 NaN
8 2016-05-31 A NL 9 1.0
9 2016-05-31 A BE 10 2.0
10 2016-05-31 A FR 11 NaN
11 2016-05-31 B NL 12 3.0
12 2016-05-31 B BE 13 4.0
13 2016-05-31 B FR 14 NaN
14 2016-05-31 C NL 15 5.0
15 2016-05-31 C BE 16 6.0
16 2016-05-31 C UK 17 8.0
17 2016-05-31 C SL 18 NaN
18 2016-06-30 A NL 19 9.0
19 2016-06-30 B FR 20 14.0
20 2016-06-30 B UK 21 NaN
21 2016-06-30 B SL 22 NaN
22 2016-06-30 C NL 23 15.0
23 2016-06-30 C BE 24 16.0
假设我们有以下数据框:
Date Type Country Value
0 2016-04-30 A NL 1
1 2016-04-30 A BE 2
2 2016-04-30 B NL 3
3 2016-04-30 B BE 4
4 2016-04-30 C NL 5
5 2016-04-30 C BE 6
6 2016-04-30 C FR 7
7 2016-04-30 C UK 8
8 2016-05-31 A NL 9
9 2016-05-31 A BE 10
10 2016-05-31 A FR 11
11 2016-05-31 B NL 12
12 2016-05-31 B BE 13
13 2016-05-31 B FR 14
14 2016-05-31 C NL 15
15 2016-05-31 C BE 16
16 2016-05-31 C UK 17
17 2016-05-31 C SL 18
18 2016-06-30 A NL 19
19 2016-06-30 B FR 20
20 2016-06-30 B UK 21
21 2016-06-30 B SL 22
22 2016-06-30 C NL 23
23 2016-06-30 C BE 24
可以用下面的代码计算:
df = pd.DataFrame([['2016-04-30','A','NL',1], ['2016-04-30','A', "BE" ,2], ['2016-04-30', 'B', 'NL',3], ['2016-04-30','B','BE',4], ['2016-04-30','C','NL',5], ['2016-04-30','C','BE',6],['2016-04-30','C','FR', 7], ['2016-04-30','C','UK',8], ['2016-05-31','A','NL',9], ['2016-05-31','A','BE',10], ['2016-05-31','A','FR',11], ['2016-05-31','B','NL',12], ['2016-05-31','B','BE',13], ['2016-05-31','B','FR',14], ['2016-05-31','C','NL',15], ['2016-05-31','C','BE',16], ['2016-05-31','C','UK',17], ['2016-05-31','C','SL',18], ['2016-06-30','A','NL',19], ['2016-06-30','B','FR',20], ['2016-06-30','B','UK',21], ['2016-06-30','B','SL',22], ['2016-06-30','C','NL',23], ['2016-06-30','C','BE',24]], columns=['Date','Type' ,'Country' ,'Value'])
我想添加一个额外的列 'ValueShifted',它基本上会随着时间的推移改变观察结果。因此,例如对于观察值 'Date: 2016-05-31, Type: B, Country: BE',我想将 'ValueShifted' 设置为 4。如果观察值在前一时期不可用,我想将其设置为 NaN。
我可以用蛮力完成,但这对我的实际数据集来说会花费太多时间。有没有办法有效地做到这一点?
预期 df:
Date Type Country Value ValueShifted
0 2016-04-30 A NL 1 nan
1 2016-04-30 A BE 2 nan
2 2016-04-30 B NL 3 nan
3 2016-04-30 B BE 4 nan
4 2016-04-30 C NL 5 nan
5 2016-04-30 C BE 6 nan
6 2016-04-30 C FR 7 nan
7 2016-04-30 C UK 8 nan
8 2016-05-31 A NL 9 1
9 2016-05-31 A BE 10 2
10 2016-05-31 A FR 11 nan
11 2016-05-31 B NL 12 3
12 2016-05-31 B BE 13 4
13 2016-05-31 B FR 14 nan
14 2016-05-31 C NL 15 5
15 2016-05-31 C BE 16 6
16 2016-05-31 C UK 17 8
17 2016-05-31 C SL 18 nan
18 2016-06-30 A NL 19 9
19 2016-06-30 B FR 20 14
20 2016-06-30 B UK 21 nan
21 2016-06-30 B SL 22 nan
22 2016-06-30 C NL 23 15
23 2016-06-30 C BE 24 16
IIUC,你想要GroupBy.shift
:
#df['Date']=pd.to_datetime(df['Date'])
#df=df.sort_values(['Date','Type']) #order if necessary
df['ValueShifted']=df.groupby(['Type','Country'])['Value'].shift()
print(df)
输出
Date Type Country Value ValueShifted
0 2016-04-30 A NL 1 NaN
1 2016-04-30 A BE 2 NaN
2 2016-04-30 B NL 3 NaN
3 2016-04-30 B BE 4 NaN
4 2016-04-30 C NL 5 NaN
5 2016-04-30 C BE 6 NaN
6 2016-04-30 C FR 7 NaN
7 2016-04-30 C UK 8 NaN
8 2016-05-31 A NL 9 1.0
9 2016-05-31 A BE 10 2.0
10 2016-05-31 A FR 11 NaN
11 2016-05-31 B NL 12 3.0
12 2016-05-31 B BE 13 4.0
13 2016-05-31 B FR 14 NaN
14 2016-05-31 C NL 15 5.0
15 2016-05-31 C BE 16 6.0
16 2016-05-31 C UK 17 8.0
17 2016-05-31 C SL 18 NaN
18 2016-06-30 A NL 19 9.0
19 2016-06-30 B FR 20 14.0
20 2016-06-30 B UK 21 NaN
21 2016-06-30 B SL 22 NaN
22 2016-06-30 C NL 23 15.0
23 2016-06-30 C BE 24 16.0
如果存在遗漏观察的可能性,最安全的方法是复制DataFrame,手动更改日期,然后才能精确合并。
df['Date'] = pd.to_datetime(df.Date)
df2 = df.copy()
df2['Date'] = df2['Date'] + pd.offsets.MonthEnd(1)
df2 = df2.rename(columns={'Value': 'ValueShifted'})
df = df.merge(df2, on=['Date', 'Type', 'Country'], how='left')
Date Type Country Value ValueShifted
0 2016-04-30 A NL 1 NaN
1 2016-04-30 A BE 2 NaN
2 2016-04-30 B NL 3 NaN
3 2016-04-30 B BE 4 NaN
4 2016-04-30 C NL 5 NaN
5 2016-04-30 C BE 6 NaN
6 2016-04-30 C FR 7 NaN
7 2016-04-30 C UK 8 NaN
8 2016-05-31 A NL 9 1.0
9 2016-05-31 A BE 10 2.0
10 2016-05-31 A FR 11 NaN
11 2016-05-31 B NL 12 3.0
12 2016-05-31 B BE 13 4.0
13 2016-05-31 B FR 14 NaN
14 2016-05-31 C NL 15 5.0
15 2016-05-31 C BE 16 6.0
16 2016-05-31 C UK 17 8.0
17 2016-05-31 C SL 18 NaN
18 2016-06-30 A NL 19 9.0
19 2016-06-30 B FR 20 14.0
20 2016-06-30 B UK 21 NaN
21 2016-06-30 B SL 22 NaN
22 2016-06-30 C NL 23 15.0
23 2016-06-30 C BE 24 16.0