工作中遇到的, 有些数据只有在交易日才有值,在非交易日会显示NaN,需要填充成前一个交易日的数据
如果每天只有一条,可以用ffill
但每天有多条, 直接用ffill是不行的
假设现有df是这样的,需要根据NaN的日期找到上一个有数据的日期, 填充一模一样的数据
期望输出的df如下,这里2018-01-02和2018-02-03都填充2018-01-01的数据
=====2020.12.31更新, 重写了个更简洁的算法代码
方法2代码如下
import pandas as pd
import numpy as np
df=pd.DataFrame(np.arange(20).reshape(5,4),columns=list('ABCD'))
df['symbol'] = ['0001.SH', '0002.SH', '0003.SH', '0004.SH', '0005.SH']
df.loc[2:3,:]=np.nan
df['the_date'] = ['2018-01-01', '2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04']
print(df)#打印结果如下
"""
A B C D symbol the_date
0 0.0 1.0 2.0 3.0 0001.SH 2018-01-01
1 4.0 5.0 6.0 7.0 0002.SH 2018-01-01
2 NaN NaN NaN NaN NaN 2018-01-02
3 NaN NaN NaN NaN NaN 2018-01-03
4 16.0 17.0 18.0 19.0 0005.SH 2018-01-04
"""
#将NaN值填充为known,否则不方便后面的处理
df.fillna('unknown',inplace=True)
#按已经连续的日期列,进行groupby
df_grouped = df.groupby(by=['the_date'])
#pre_df和new_df用于填充
pre_df = pd.DataFrame()
new_df = pd.DataFrame()
#循环遍历按日期分组后的dataframe
for i in df_grouped:
#取出单天的dataframe
df_day = i[1]
#设置日期为index,方便后面取出其他列的值并判断其他列的值是不是unknown
df_day.set_index('the_date',inplace=True)
#判断如果单天dataframe的值都为unknown
if (df_day.values=='unknown').all():
#取出上一天的dataframe,并把日期设置为今天,即该天填充了上一日数据形成了一个新的dataframe
pre_df.loc[:,'the_date']=df_day.index.values[0]
#将上一步结果赋值, 待后面添加到new_df
df_fill = pre_df
else:#否则,将今日的单天dataframe赋值,待后面添加到new_df
df_fill=df_day.reset_index()
#将每次循环的结果添加给new_df
new_df = new_df.append(df_fill)
#pre_df更新为每次的填充dataframe,以便下次使用
pre_df = df_fill
print(new_df)#打印结果如下,数据填充完成
"""
the_date A B C D symbol
0 2018-01-01 0.0 1.0 2.0 3.0 0001.SH
1 2018-01-01 4.0 5.0 6.0 7.0 0002.SH
0 2018-01-02 0.0 1.0 2.0 3.0 0001.SH
1 2018-01-02 4.0 5.0 6.0 7.0 0002.SH
0 2018-01-03 0.0 1.0 2.0 3.0 0001.SH
1 2018-01-03 4.0 5.0 6.0 7.0 0002.SH
0 2018-01-04 16.0 17.0 18.0 19.0 0005.SH
"""
=======以下是最初的写法,比较繁琐
方法1代码如下:
import pandas as pd
import numpy as np
def fill_nan(df,col,fill_col):
valid_index = df[col].first_valid_index()
df = df.iloc[valid_index:, :]
df[col] = df[col].fillna('unknown')
df.set_index([fill_col],inplace=True)
nan_index = df[df[col]=='unknown'].index.tolist()
df2 = df.reset_index()
for i in nan_index:
pre_index = df2[df2[fill_col]==i].index.tolist()[0]-1
pre_day = df2.loc[pre_index,fill_col]
fill_frame = df2[df2[fill_col]==pre_day]
fill_frame[fill_col]=i
df2 = df2.append(fill_frame)
df2=df2[~((df2[fill_col]==i)&(df2[col]=='unknown'))]
df2 = df2.sort_values(fill_col).reset_index(drop=True)
return df2
if __name__=='__main__':
df=pd.DataFrame(np.arange(20).reshape(5,4),columns=list('ABCD'))
df['symbol'] = ['0001.SH', '0002.SH', '0003.SH', '0004.SH', '0005.SH']
df.loc[2:3,:]=np.nan
df['the_date'] = ['2018-01-01', '2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04']
print(df)
df = fill_nan(df,'symbol',"the_date")
print(df)