pandas系列 - (三)關於時點時期資料的處理
阿新 • • 發佈:2020-10-21
實際工作場景中,會遇到需要處理時序表。對於少量的時點時序資料,明細資料+資料透視表,也是很快能處理完成。大量的話,可能會出現有一點慢,同時一些計算欄位的每次都要設定,不太方便處理。整理一個思路:將系統的時點時序資料進行彙總整合,並形成時序表。
思路:結構化的資料是很方便處理,表格類的資料不方便程式處理,但是方便計算欄位。所有思路是, 將制定指標歸併,形成資料資料透視表,再通過列運算形成計算欄位,再轉回明細資料,最終根據自己 的需要進行處理。 1、資料來源讀取; 2、資料指標歸併,將A1、A2指標,歸併為A,歸併的參照表以EXCEL的形式儲存; 3、資料彙總,用於原始資料是單個地方資料,比如通過彙總關係,彙總出華北地區,華南地區資料; 4、增加計算欄位,比如:原始資料中有銷售額、銷售人數,通過參照表:形成 人均銷售額 = 銷售額/銷售人數。 5、增加相對資料,一般時點資料都是當期值,用於分析的化,還需要知道“比上期”、“比年初”、“同比”等值、
主函式:
%%time # 獲取源資料 df = get_src_data(r'data/input/20200930 zonghe3/' ) date_format = "%Y%m%d" stack_drop = False # 不刪除指標為空的指標 # 保留基礎資料,儲存共有多少機構產品 df_base = df.loc[:,['機構名稱','產品品種','資料管理機構']].drop_duplicates(subset =['機構名稱','產品品種'],keep='first') # 資料預處理 df = pre_handle_data(df) # 讀取參照表,參照表存放指標的歸併關係,以及計算欄位的公式dfcz = pd.read_excel(r'data/input/cz-zgbgst.xlsx',dtype=object,sheet_name=0) df['指標名稱'] = df['行指標名稱'] + df['列指標名稱'] # 資料歸併 df = reduce_data(df) # 資料彙總 df = hz_data(df) # 計算欄位,df是處理過後的原始資料來源 df = calcu_data(df) # 在原始資料來源的基礎上,計算出相對資料 df_deal = calcu_relative_data(df)
1、資料來源讀取:
# 獲取資料來源 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 reduce_data(df): # 篩選欄位 # 選擇需要的數 df = df[df['指標名稱'].isin(dfcz.loc[dfcz['是否篩選'] == 1,'指標名稱'].values.tolist())].copy() # 內容轉換 df['指標名稱'] = df['指標名稱'].replace(dfcz['指標名稱'].values.tolist(),dfcz['對應'].values.tolist()) df.drop(columns=['行指標名稱', '列指標名稱', '資料表名稱','機構產品標識'],inplace=True) return df
3、增加計算欄位,遍歷參照表中的計算欄位名,以及對應公式,使用df.eval進行計算。
# 計算欄位,通過現有指標,計算出新的指標 def calcu_data(df): # 補充沒有的列名,形成差集,補充新的列,這裡是為了避免最後計算時造成的誤差 dft = dfcz[(dfcz['對應'].notnull())].drop_duplicates(subset =['對應'],keep='first') for dyl in dft['對應'].values.tolist(): if not dyl in list(df.columns): df[dyl] = 0.0 # 根據計算過程,得出計算欄位 df.fillna(0,inplace = True) # 填0,防止影響後面計算 zbmcdf = dfcz[(dfcz['計算欄位'].notnull()) & dfcz['計算過程'].notnull()].drop_duplicates(subset =['計算欄位'],keep='first') for i,row in zbmcdf.iterrows(): df[ str(row['計算欄位'])] = df.eval(str(row['計算過程'])) #將佔比的列補充一個(%) dname = {} for c in df.columns: if str(c).find('佔比') != -1 or str(c).find('率') != -1 or str(c).find('比率') != -1 or str(c).find('淨值') != -1: if str(c).find('%') == -1: dname[str(c)] = str(c) + '(%)' if len(dname) > 0 : df.rename(columns=dname,inplace = True) # 將資料打散為明細 dfout = df.set_index(['資料日期', '產品品種', '機構名稱']) dfout.columns.names = ['指標名稱'] dfout[dfout == 0] = np.nan dfout.dropna(axis=1,how='all',inplace=True) # 刪除空列,減少後面的計算 dfout = dfout.stack(dropna = True).reset_index() # 這裡將新形成的指標轉置,如果是空的話,擇不保留。 dfout.rename(columns={0:'00 當期值'},inplace = True) return dfout
返回資料型別:
4、增加相對資料,使用apply逐行增加比上期,比年初,同比增速,同比增減資料。
# 增加相對計算欄位 def calcu_relative_data(df): # 計算相對數 calcu_relative_data # 生成日期範圍列表 date_list = list(set(df['資料日期'].values.tolist())) # 構建唯一索引 df['unique'] = df['資料日期'] + ' ' + df['產品品種'] + ' ' + df['機構名稱']+ ' ' + df['指標名稱'] dftest = df.set_index('unique',drop=False) df.drop(columns=['unique'],inplace=True) dftest.fillna(0,inplace = True) # 填0,防止影響後面計算 # 計算前可以考慮做好,缺失值轉換為0 dftest['10 比上期'] = dftest.apply(add_huanbi,axis=1,args=(dftest,date_list,'資料日期','unique','00 當期值')) dftest['11 比上期-同比增減'] = dftest.apply(add_huanbi_onyear,axis=1,args=(dftest,date_list,'資料日期','unique','00 當期值')) dftest['20 比年初'] = dftest.apply(add_binianchu,axis=1,args=(dftest,date_list,'資料日期','unique','00 當期值')) dftest['21 比年初-同比增減'] = dftest.apply(add_binianchu_onyear,axis=1,args=(dftest,date_list,'資料日期','unique','00 當期值')) dsel = dftest['指標名稱'].str.contains('%') dftest.loc[~dsel,'30 同比增速'] = dftest[~dsel].apply(add_tongbizengsu,axis=1,args=(dftest,date_list,'資料日期','unique','00 當期值')) # 根據指標名稱,包含%只需要增加同比增減,不包含的化計算增速 dftest.loc[dsel,'31 同比增減'] = dftest[dsel].apply(add_tongbi,axis=1,args=(dftest,date_list,'資料日期','unique','00 當期值')) dftest = dftest.reset_index(drop=True) dftest.drop(columns=['unique'],inplace=True) dftest = dftest.set_index(['資料日期', '產品品種', '機構名稱', '指標名稱']) dftest.columns.names = ['資料型別'] # 這裡可以考慮設定 dropna = False ,這樣的話,就可以保持空值存在。 dftest[dftest == 0] = np.nan dftest = dftest.stack(dropna = True).reset_index() # 將資料轉化為臺賬型別 dftest.rename(columns={0:'資料值'},inplace = True) #這裡把不需要的刪除 if stack_drop == False: dftest.drop(index=dftest[ (~(dftest['指標名稱'].str.contains('%'))) & (dftest['資料型別'] == '31 同比增減') ].index,inplace=True) dftest.drop(index=dftest[ ((dftest['指標名稱'].str.contains('%'))) & (dftest['資料型別'] == '30 同比增速') ].index,inplace=True) return dftest
最終輸出樣式是:
資料日期 產品品種 機構名稱 指標名稱 資料型別 資料值
A A A A 當期數 XX
最後,可以通過再處理一次pivot_table資料透視表得到想到的時序資料。後續,只需要修改參照表就可以快速轉換成其他資料。