DataFrame按日期字段填充NaN值, 填充成前一天的所有数据

工作中遇到的, 有些数据只有在交易日才有值,在非交易日会显示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)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
如果在使用DataFrame的fillna方法填充0后,数据仍然包含NaN,可能是因为fillna方法没有功地将所有的NaN替换为0。这种情况下,有几种可能的原因和解决方法: 1)检查数据类型:首先,确保要填充的列的数据类型是数型(如整数或浮点数),因为fillna方法只能用于数型列。如果列的数据类型是字符串或其他类型,并且包含NaN,fillna方法不会生效。可以使用astype方法将列的数据类型转换为数型,然后再尝试使用fillna方法。 2)检查缺失位置:确认NaN的确实位置,可能是在填充没有正确地定位到缺失。可以使用isna方法检查DataFrame中的NaN,并观察其所在的行和列。然后,可以使用loc或iloc方法来访问和修改具体位置上的。 3)指定inplace参数:确保在调用fillna方法时,指定了inplace参数为True,以便直接在原始DataFrame上修改数据,而不是返回一个新的副本。如果没有指定inplace参数或设置为False,默认会返回一个新的填充后的DataFrame。 以下是一个示例代码,演示如何使用fillna方法填充0并处理NaN: ```python import pandas as pd # 创建一个包含NaNDataFrame示例 df = pd.DataFrame({'A': [1, 2, np.nan, 4, 5], 'B': [6, np.nan, 8, 9, 10]}) # 使用fillna方法填充0,并指定inplace参数为True df.fillna(0, inplace=True) # 检查是否还存在NaN print(df.isna().sum()) ``` 如果仍然存在NaN,可能需要进一步检查数据和代码,确定出现NaN的原因,并采取适当的处理方法。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值