pandas系列 - (二)关于两期时点数据的比较
统计数据来说,有时点数据和时期数据。通常情况下,会进行两期数据的比较,现整理一个两期数据比较的场景应用。主要流程分为:
1、数据读取
2、数据预处理
3、数据分类汇总
4、两期数据比较
5、数据输出到EXCEL
主程序如下:
df = get_src_data(r'../data/learn_pandas/20200930 zongheqixian/') # 预处理数据 df = pre_handle_data(df) df = hz_data(df) # 进行数据比较 df = compare_data(df,'20200930','20200831') df.sort_values(by=['产品品种','机构名称', '数据表名称','列指标名称','行指标名称'],inplace=True) name = r'data/output/20200930 数据审核.xlsx' with pd.ExcelWriter(name) as writer: df.to_excel(writer,'仅合计项',index=False,freeze_panes=(1,6)) # freeze_panes可以EXCEL设置冻结位置 writer.save()
1、源数据读取,出入文件夹作为参数,合并所有源数据到一起。使用pd.concat进行数据合并。
# 获取数据源 def get_src_data(folder_name): file_list = os.listdir(folder_name) ldf = [] # 先放入list,最后一起concat比较高效率 if len(file_list) > 0 : # 遍历文件夹下所有文件 for i in range(len(file_list)): # 如果是excel择用这个,如果是csv择用另一个 ldf.append(pd.read_excel(folder_name + str(file_list[i]),dtype=object)) return pd.concat(ldf,ignore_index=True) else: return None
2、进行数据预处理,如单位转换,不需要的数据剔除。
# 数据预处理,指标归并、数据删除 def pre_handle_data(df): # 预处理数据 return df
3、由于当前处理的数据是单机构的数据,想进行汇总查看整体数据情况。使用pivot_table进行汇总,接着使用reset_index转化为明细项进行合并到源数据中。
def hz_data(df): # 分产品、全部汇总 hz_list = [] table = pd.pivot_table(df,values=['数据值'],index=['数据日期','产品品种','数据表名称', '行指标名称', '列指标名称'],aggfunc=np.sum,fill_value = 0) table.reset_index(inplace=True) table['机构名称'] = '# 合计 ' + table['产品品种'] hz_list.append(table) table = pd.pivot_table(df,values=['数据值'],index=['数据日期','数据表名称', '行指标名称', '列指标名称'],aggfunc=np.sum,fill_value = 0) table.reset_index(inplace=True) table['机构名称'] = '# 合计 ' table['产品品种'] = '# 合计 ' hz_list.append(table) hz_list.append(df) return pd.concat(hz_list,ignore_index=True)
4、进行两期数据比较,将数据拆分成两个时点,并使用pd.merge拼接到一起。
# 数据比较 def compare_data(df,cur_date,pre_date): # 进行拼接 cur = df[df['数据日期'] == cur_date].copy() pre = df[df['数据日期'] == pre_date].copy() pre.drop(columns=['数据日期','数据ID','指标ID','行序号','列序号', '数据表序号', '数据位数','数据批次'],inplace=True) cur.drop(columns=['数据ID','指标ID','行序号','列序号', '数据表序号', '数据位数','数据批次'],inplace=True)
# on为合并依赖字段 df = pd.merge(cur,pre,how='outer',on=[ '行指标编码', '行指标名称', '列指标编码', '列指标名称', '数据表名称', '数据管理机构', '产品品种', '机构名称', '社会信用代码','机构产品标识'],suffixes=['_当期','_上期']) # 列位置调整 df = df[order] # 修改一个列名 df.rename(columns={'数据值_当期':'当期值(亿元/只)','数据值_上期':'上期值(亿元/只)'},inplace = True) # 删除无用列名 df.drop(columns=['社会信用代码','行指标编码', '列指标编码','机构产品标识'],inplace=True) # 补充数据日期,注意这里要先补充缺失字段,否则进行批量计算的时候,会跳过空值,因此要先fillna(0) df['数据日期'] = cur_date df.fillna(0,inplace=True) df['变动值'] = df['当期值(亿元/只)'] - df['上期值(亿元/只)'] dfsel = ~(df['上期值(亿元/只)'] == 0) df.loc[dfsel,'变幅(%)'] = df.loc[dfsel,'变动值'] / df.loc[dfsel,'上期值(亿元/只)'] # 增加比例判断 df.loc[(abs(df['变幅(%)'])>0.3) & (abs(df['变幅(%)'])<1),'备注'] = "变幅大于30%" df.loc[(abs(df['变幅(%)'])>=1) & (abs(df['变幅(%)'])<100),'备注'] = "变幅大于100%" df.loc[(abs(df['变幅(%)'])>=100),'备注'] = "变幅大于100倍" df.loc[df['上期值(亿元/只)'].isnull(),'备注'] = '本期新增' df.loc[df['当期值(亿元/只)'].isnull(),'备注'] = '上期有,本期无' df[df == 0] = np.nan return df
5、最后输出,见主程序。