Updated 22 Oct. 2018: I have the following dataset:
data = [('D',1,10,8),
('D',2,12,12),
('X',1,28,np.NaN),
('D',3,np.NaN,np.NaN),
('X',2,np.NaN,25),
('X',3,32,25),
('T',1,220,np.NaN),
('X',4,30,np.NaN),
('T',2,240,np.NaN),
('X',2,38,np.NaN),
('T',3,np.NaN,np.NaN),
('T',4,200,150)]
labels = ['item', 'month','normal_price','final_price']
df = pd.DataFrame.from_records(data, columns=labels)
item month normal_price final_price
0 D 1 10.0 8.0
1 D 2 12.0 12.0
2 X 1 28.0 NaN
3 D 3 NaN NaN
4 X 2 NaN 25.0
5 X 3 32.0 25.0
6 T 1 220.0 NaN
7 X 4 30.0 NaN
8 T 2 240.0 NaN
9 X 2 38.0 NaN
10 T 3 NaN NaN
11 T 4 200.0 150.0
I want to fill NaN
in the 'normal_price'
, 'final_price'
columns for each item with the 'normal_price'
, 'final_price'
of its preceding month (if not available by its succeeding month). I have tried using this:
df[['normal_price','final_price']]=df[['normal_price','final_price']].fillna(method='ffill')
but it gives me this:
item month normal_price final_price
0 D 1 10.0 8.0
1 D 2 12.0 12.0
2 X 1 28.0 12.0*
3 D 3 28.0* 12.0
4 X 2 28.0 25.0
5 X 3 32.0 25.0
6 T 1 220.0 25.0*
7 X 4 30.0 25.0
8 T 2 240.0 25.0*
9 X 2 38.0 25.0
10 T 3 38.0* 25.0*
11 T 4 200.0 150.0
The problem is with cases with an asterisk (I've also tried 'bfill'
). These values should be filled with based on their correct items. Ideally, I should get:
item month normal_price final_price
0 D 1 10.0 8.0
1 D 2 12.0 12.0
2 X 1 28.0 25.0
3 D 3 12.0 12.0
4 X 2 28.0 25.0
5 X 3 32.0 25.0
6 T 1 220.0 150.0
7 X 4 30.0 25.0
8 T 2 240.0 150.0
9 X 2 38.0 25.0
10 T 3 220.0 150.0
11 T 4 200.0 150.0
I have also tried the followings (from answers offered by date):
df[['normal_price','final_price']].ffill(limit=1).bfill(limit=1)
or
df[['normal_price','final_price']]=df[['normal_price','final_price']].interpolate(method='nearest')
But none of them are giving me reasonable fillna corresponding to each item. I have found this method:
df[['normal_price','final_price']]=df[['normal_price','final_price']].fillna(df.groupby(['item'])[['normal_price','final_price']].transform('mean'))
It works better, BUT it introduces unpredictable values (in this case the 'mean'
) for NaN
values, not with the preceding or following values as I originally wanted. I am trying to combined the df.groupby(['item'])
concept with '.ffill'
or '.bfill'
, but so far no success.