先上标题!!!踩坑记录 - 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文件。