算是雜記,經常在微信里看到9塊9學python處理excel,一直沒機會。正好最近有個本科室友找我,問能不能給他處理個工程測算表,指明了要用python來做。本科的鐵哥們,這忙咱得幫。說干就干,首先當然是不去報班買9塊9的課程。
首先,看看要處理的表是啥樣,他想要的處理結果是啥樣
老鐵做測量多年,用excel表滑溜的很,他是為了報單位的創新項目,所以才想用python提高一下科技含量。他對自己要處理的表和處理成啥樣了然于心。
原表是一張arcgis導出的各地類的測量面積表,里面有上千個圖斑,也就對應著上千條記錄。要處理成一張匯總表,根據項目、鎮界統計各地類的面積。看著不算難,但是各類統計以及按格式填表,著實讓我忙活了一陣。
以下為原始數據表:
統計匯總表:
可以從匯總表中看到,統計分兩個維度,一個是根據項目及鎮、村來統計各地類的總面積,還有一個維度是統計該區域內各地類的總面積。
高效統計法推薦
這里不得不提到一個python庫——pandas,能夠像操作數據庫那樣進行分組操作。
data_arcgis = pd.read_excel(inputfile, inputsheetname)
grp1 = data_arcgis.groupby(['權屬', '鎮界', '界線', 'DLMC', '地類', '分區']).agg({'畝': ['sum']}).reset_index()
通過權屬、鎮界、地類等對原始數據進行最小粒度的分組,這樣操作就能獲得最小粒度數據,為后面的匯總打下數據基礎
grp3 = grp2.groupby(['鎮界'])
Town_list = list(grp3.groups.keys()) ###獲取鎮界枚舉值
通過該方法獲得組內的枚舉值,為寫入匯總表里的鎮、村準備數據源
for town in Town_list:
grp4 = grp2[grp2['鎮界'] == town]
grp5 = grp4.groupby(['分區'])
Fq_list = list(grp5.groups.keys()) ###獲取分區枚舉值
town_total = grp4.agg({'畝': ['sum']}).reset_index()['畝'].iloc[0,0]
#print(town + ':' + str(town_total))
sheet.cell(row = startrowindex + lineindex, column=4).value = town
sheet.cell(row = startrowindex + lineindex, column=4).font = font
sheet.cell(row = startrowindex + lineindex, column=8).value = town_total
sheet.cell(row = startrowindex + lineindex, column=8).font = font
lineindex = lineindex + 1
for fq in Fq_list:
grp6 = grp4[grp4['分區'] == fq]
grp7 = grp6.groupby(['界線'])
Jx_list = list(grp7.groups.keys()) ###獲取界線枚舉值
for jx in Jx_list:
grp8 = grp6[grp6['界線'] == jx]
grp9 = grp8.groupby(['地類'])
Dl_list = list(grp9.groups.keys()) ###獲取地類枚舉值
jx_total = grp6[grp6['界線'] == jx].agg({'畝': ['sum']}).reset_index()['畝'].iloc[0,0]
#print(' ' + fq + ':' + jx + ':' + str(jx_total))
sheet.cell(row = startrowindex + lineindex, column=2).value = fq
sheet.cell(row = startrowindex + lineindex, column=2).font = font
sheet.cell(row = startrowindex + lineindex, column=5).value = jx
sheet.cell(row = startrowindex + lineindex, column=5).font = font
sheet.cell(row = startrowindex + lineindex, column=8).value = jx_total
sheet.cell(row = startrowindex + lineindex, column=8).font = font
for dl in Dl_list:
dl_total = grp8[grp8['地類'] == dl].agg({'畝': ['sum']}).reset_index()['畝'].iloc[0,0]
dic_dl_value[dl] = dic_dl_value[dl] + dl_total
total_sum = total_sum + dl_total
sheet.cell(row = startrowindex + lineindex, column=dic_dl_column[dl]).value = dl_total
sheet.cell(row = startrowindex + lineindex, column=dic_dl_column[dl]).font = font
#print(' ' + dl + ':' + str(dl_total))
lineindex = lineindex + 1
依次遍歷鎮界、分區、界線、地類,最后在地類循環中,對相同地類進行累計求和。至此就可以獲得相應鎮界、分區、界線下的地類匯總面積,同時通過lineindex來計算寫入的行號,保證了運算結果寫入到爭取的行列內。
令人頭疼的難點
方法不難,最頭疼的還是原始數據的不規范帶來的不必要的程序消耗。因為原始數據中地類寫入的隨意性,以及新增臨時地類(即不在匯總表內的地類),則需要進行額外的處理。
處理原則是,只要原始數據中地類名稱有和匯總表內的字段名相匹配的,則認為命中,記錄下該字段在excel中的列號,如果不在,則放入匯總表內的最后列。程序跑完后,由人工介入處理。
def setDlcolumn(all_dl_list, dl_type_series, dic_dl_column):
dl_column_length = dl_type_series.shape[0]
dl_column_length_bak = dl_column_length
for dl_target in all_dl_list:
colum_index = 0
flag = 0
for dl_type in dl_type_series.array:
colum_index = colum_index + 1
if str(dl_type) == 'nan':
continue
if dl_target in dic_dl_column and dic_dl_column[dl_target] < dl_column_length_bak: ###字典里已存在該地類
flag = 1
break
if dl_target in dl_type: ###如果arcgis中地類包含在樣表中,則記錄下列號
flag = 1
dic_dl_column[dl_target] = colum_index
break
if flag == 0:
dl_column_length = dl_column_length + 1
dic_dl_column[dl_target] = dl_column_length
return dic_dl_column
處理效果
最后輸出的結果,數值和統計結果一致,樣式上還有所欠缺,需要利用openpyxl對表格進行樣式修飾。基本達到老鐵預期。