2021-10-27 pandas的填充fillna 与 pandas的df[columns_list]重新生成datafrmae的踩坑指南

先上标题!!!踩坑记录 - pandas填充和非填充的区别以及df=df[cols_list]的重点注意事项

以下疑难杂症,你可能永远不会遇到,就像我以前只是用pandas做自己熟悉的事情,使用相对成熟、稳定的数据源。然鹅,某一天开始工作转向了,开始要用到一些非标的数据、人工定义的一些数据。悲剧就开始发生了

踩坑一

df_fillna0 = pd.read_excel('filename',sheet_name='xxx').fillna(0)
df_nofillna = pd.read_excel('filename',sheet_name='xxx')
如此操作的时候有哪些注意点,

造数据,下文Python读取相同的数据,Excel截图如下:

有A B C 三个项目,A项目近6天内都有数据,B项目只有最近4天的数据,C项目只有最近2天的数据,业务要求对不同项目进行统计运算。
为展示方便,只给近几天的数据,而真是的财务数据可能是N个项目,从几年前开始的累计。
在这里插入图片描述

# 填充和不填充的方式,读取excel文件,对列字段做整理 
df_fillna0 = pd.read_excel(r'demo1.xlsx').fillna(0)
df_fillna0.columns = [str(str(col)[:10]) for col in df_fillna0.columns] 
df_fillna0.set_index('项目', inplace=True)

df_fillnona = pd.read_excel(r'demo1.xlsx')
df_fillnona.columns = [str(str(col)[:10]) for col in df_fillnona.columns] 
df_fillnona.set_index('项目', inplace=True)

df_fillna0,df_fillnona

output1:
在这里插入图片描述

# 最主要的差别就是对数据进行运算时,计数公式会过滤掉NA值,但不过滤0值。
df_fillna0.mean(axis=1),df_fillnona.mean(axis=1)

output2:
在这里插入图片描述
我们可以检验下

df_fillna0.count(axis=1),df_fillnona.count(axis=1)

output3:
在这里插入图片描述

其实看完之后都会感觉很简单,而工作中的问题就在于要理解业务过程,项目没发生填充了0,就改变了业务的真实记录,这会导致后续的所有跟计数结果关联的运算都发生错误。

踩坑二

cols_list = df.columns.tolist()[3:]
df1 = df[cols_list]
这种用法会出现什么问题,以及需要怎样解决

造数据,下文中python引用相同数据。数据说明:依然是项目每日的发生额数值数据,但记录的特点;图标标出颜色的部分,在当年1月1日之后一次记录每天的发生额数据,1月1日之前不保留历史的每天数据,只记录之前每月的日平均发生额,并以每月低的日期为表头进行记录。

而业务的需求之一,就是要计算当年的日平均额
在这里插入图片描述

解决思路:因数据是按日新增,且当年的每月平均值是放在1月1日前一列,可以看出有一定的规律性,只需要在计算年日均值的时候将1月1日之前的数据全部剔除,然后求均值运算即可

初次填坑的尝试

# 数据读取、整理
df_demo2 = pd.read_excel(r'demo2.xlsx', index_col=[0])
df_demo2.columns = [str(str(col)[:10]) for col in df_demo2.columns]
del df_demo2['年日均']

# 找到当前年度1月1日的位置,取出索引值,然后按索引只取之后的列字段,重构新的dataframe
def get_startday_index(df):
    import datetime
    today = datetime.datetime.today()
    current_year = today.year
    init_date = '{}-01-01'.format(current_year)  # 获取当年的1月1日
    cols = df.columns
    new_cols = []
    for i, val in enumerate(cols):
        if val == init_date:
            new_cols = cols[i:]
            df_new = df[new_cols]
            return df_new
            break    #  遍历每个字段,遇到1月1号的时候就跳出for循环,返回字段列表的索引值,只取该索引之很多字段

函数调用,输出结果:
在这里插入图片描述

问题来了,为啥只少了一列,不应该是少两列吗。可以看到调用函数新生成的df当中出现了两个1月31日。这又是什么原因。后来又尝试了其他同样针对列字段进行的清洗方法发现都是同样的问题,个人推测,df[col]这样重新生成df的方法[]方括号属于包含关系的判断, 即用新的字段列表的值去原来的字段列表中去进行匹配,只要原来的字段列表中在新的字段列表当中,就都会取出来

此法不行后,转换思路,使用转置的办法,对行索引进行操作就完全避免了这个问题

df_t = df_demo2.T

for i, val in enumerate(df_t.index.values):
    if val == init_date:
        print(i)
        df_t = df_t.iloc[i:]
        break
df_t2 = df_t.T
df_t2  

正确结果输出:
在这里插入图片描述
如此完美解决,就可以进行后续的运算了

希望上面的踩坑经历能够帮助到你, 如果有更好的解决方案,请不要吝啬

工作平台,vscode – ipynb文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值