從多層文件夾的多個(gè)excel中統(tǒng)計(jì)匯總各個(gè)文件夾和各個(gè)excel的全部SHEET中的指定數(shù)據(jù)。
一個(gè)文件夾,里面有多個(gè)子文件夾和多個(gè)excel表格,每個(gè)子文件夾里面也有多個(gè)子文件夾和多個(gè)excel表格,每個(gè)excel表格中有若干個(gè)SHEET。
每個(gè)excel表是每個(gè)員工自己制作的表格,其中每個(gè)sheet存儲(chǔ)著每個(gè)月的報(bào)銷(xiāo)清單,每個(gè)文件夾分類存放著每個(gè)小組的表格,這些小組的表格又放在他們的部門(mén)文件夾里,每個(gè)部門(mén)的文件夾放在分公司的文件夾里,再按分公司命名后放到總公司的文件夾里。
現(xiàn)在要統(tǒng)計(jì)里面的金額和條目數(shù),金額所在的列名,有的叫“(金 額)”,有的叫“B_A.金額”,這種里面只有“金額”兩個(gè)漢字的要統(tǒng)計(jì),還有的列叫“已報(bào)銷(xiāo)金額”,這種的不能被統(tǒng)計(jì)。
(總之,文件夾很多,層次很深,表格文件很多,可能還有其他非表格文件,SHEET很多,奇葩列名也有)
統(tǒng)計(jì)結(jié)果要按分公司、部門(mén)、小組、員工的層級(jí)分組。
實(shí)現(xiàn)
我把各個(gè)分公司的文件夾放在同一個(gè)文件夾中,給這個(gè)文件夾起個(gè)名字,叫“文件放這里”,然后用python編程來(lái)搞定這個(gè)統(tǒng)計(jì)任務(wù),運(yùn)行之前保證這個(gè)文件夾的所有文件沒(méi)有被其他軟件占用。
import os
import re
import pandas as pd
class 目錄樹(shù):
def __init__(self):
self.當(dāng)前目錄=''
self.子樹(shù)=[]
self.表格文件=[]
self.各文件的總金額=[]
self.各文件的總?cè)舜?[]
def 構(gòu)建樹(shù)(目錄):
樹(shù) = 目錄樹(shù)()
樹(shù).當(dāng)前目錄 = 目錄
for i in os.listdir(目錄):
path = 目錄+os.sep+i
#print('讀取目錄',path)
if os.path.isdir(path):
樹(shù).子樹(shù).append(構(gòu)建樹(shù)(path))
elif os.path.isfile(path):
if len(i)> 4 and i[-4:]=='.xls'or len(i)> 5 and i[-5:]=='.xlsx':
樹(shù).表格文件.append(path)
總金額=0
總?cè)舜?0
#讀一下表格
for df in pd.read_excel(path,sheet_name=None).values():
cs = df.columns.to_list()
#統(tǒng)計(jì)一下金額和人次(條目數(shù))
for i in cs:
if '金額' == ''.join(re.findall("[^A-Za-z0-9_().\s]",i)):
總金額 += df[i].sum()
總?cè)舜?+= df[i].count()
break
樹(shù).各文件的總金額.append(總金額)
樹(shù).各文件的總?cè)舜?append(總?cè)舜?
return 樹(shù)
def 遍歷樹(shù)(節(jié)點(diǎn),索引表,索引棧,金額列表,人次列表):
#節(jié)點(diǎn)入棧
索引棧.append(os.path.basename(節(jié)點(diǎn).當(dāng)前目錄))
#遍歷子節(jié)點(diǎn)
for 子節(jié)點(diǎn) in 節(jié)點(diǎn).子樹(shù):
遍歷樹(shù)(子節(jié)點(diǎn),索引表,索引棧,金額列表,人次列表)
#遍歷文件
for i in zip(節(jié)點(diǎn).表格文件,節(jié)點(diǎn).各文件的總金額,節(jié)點(diǎn).各文件的總?cè)舜?:
索引棧.append(os.path.basename(i[0]).rstrip('.xlsx').rstrip('.xls'))
索引表.append(tuple(索引棧[1:]))
金額列表.append(i[1])
人次列表.append(i[2])
索引棧.pop(-1)
#節(jié)點(diǎn)出棧
索引棧.pop(-1)
path = os.getcwd()
l1 = os.listdir(path)
if '文件放這里' in l1:
path = path+os.sep+'文件放這里'
根節(jié)點(diǎn) = 構(gòu)建樹(shù)(path)
索引表=[]
索引棧=[]
人次列表=[]
金額列表=[]
遍歷樹(shù)(根節(jié)點(diǎn),索引表,索引棧,金額列表,人次列表)
df = pd.DataFrame(索引表)
df['人次']=人次列表
df['金額']=金額列表
df = df.set_index([0,1,2,3])#分組層級(jí)有四層
df#這個(gè)df就是我要的結(jié)果
把多個(gè)excel文件中的SHEET1按其中的一列分組,每一組創(chuàng)建一個(gè)以該組的名稱命名的文件夾,把每一組的數(shù)據(jù)放進(jìn)一個(gè)excel表格(文件名還是原來(lái)的),再分別放到對(duì)應(yīng)組的文件夾中。
解決方法就像是郵遞員送信,把原始數(shù)據(jù)存放的文件夾(沒(méi)有子文件夾)和新的文件夾、代碼運(yùn)行目錄放在同一目錄下,然后運(yùn)行下面這個(gè)即可。有些列可能會(huì)從文本變?yōu)閿?shù)字,如果不想改變需要在讀取表格時(shí)設(shè)置converters。
import pandas as pd
import os
分組的列名="什么"
原始表格所在的文件夾='原始數(shù)據(jù)文件夾'
新表格存放的文件夾 = '新建文件夾'
for i in os.listdir(原始表格所在的文件夾):
df = pd.read_excel('{}{}'.format(原始表格所在的文件夾,os.sep+i),converters={i:str for i in ['必需保留原文的列1的字段名','必需保留原文的列2的字段名']})
a = df[分組的列名].drop_duplicates()
for j in a.values:
k = df[df[分組的列名]==j]
r = k.set_index(df.columns.values[0])
new_dir ='{}{}'.format(新表格存放的文件夾,os.sep+j)
if not os.path.exists(new_dir):
os.mkdir(new_dir)
r.to_excel(new_dir+'{}.xlsx'.format(os.sep+i.split('.')[0]))
合并excel
在逐行讀取CSV的時(shí)候,遇到換行符會(huì)被認(rèn)為是不同的行,然而,有的數(shù)據(jù)項(xiàng)本身就存在換行符“\n”……
辦法是加一個(gè)字段數(shù)校驗(yàn),每次必須讀入足夠的內(nèi)容:
with open('a.csv','r') as f:
for line in f:
s = line.split(',')
print(s)
l = len(s)
break
n0=eval('['+input('輸入要統(tǒng)計(jì)求和的每個(gè)統(tǒng)計(jì)量的索引,用半角逗號(hào)分割:')+']')
sum0=[0 for i in n0]
is_all=True
for line in f:
print(line)
if is_all:
s = line.split(',')
else:
new = line.split(',')
s[-1] = s[-1]+new[0]
s += new[1:]
if len(s)==l:
is_all=True
j=0
for i in n0:
sum0[j]+=eval(s[i])
j+=1
else:
is_all=False
print(sum0)
輸出表格的格式怎么修改
參考這個(gè):改to_excel()格式
寫(xiě)成python函數(shù)——直接在原有的表格上改變格式:
def format_excel(filepath):
if filepath[-4:].lower()=='.xls' or filepath[-5:].lower()=='.xlsx':
dfs= pd.read_excel(filepath,sheet_name=None)
writer = pd.ExcelWriter(filepath,engine="xlsxwriter")
for sname,df in dfs.items():
for cname in df:
#對(duì)長(zhǎng)整數(shù)轉(zhuǎn)換存儲(chǔ)格式,避免精度丟失
if df[cname].dtype == 'int64' and (df[cname]>9999999).any():
df[cname] = df[cname].astype('object')
df.to_excel(writer, sheet_name=sname,index=False)
#格式化輸出
workbook = writer.book
worksheets = writer.sheets
#在這里自定義表頭格式
header_format = workbook.add_format({'font_size': 9,'border': 0,'bold':True})
##在這里自定義每一列的單元格格式
cell_format = workbook.add_format({'font_size': 9,'border': 0})
for sname, df in dfs.items():
worksheet = worksheets[sname]
#每列改一遍
for col_num, value in enumerate(df.columns.values):
worksheet.write(0, col_num, value, header_format)
worksheet.set_column(col_num,col_num, len(value)*1.6, cell_format)
writer.save()
writer.close()
print('文件“{}”格式化已完成'.format(filepath))
else:
print('文件“{}”不是電子表格'.format(filepath))
(未完待續(xù),更過(guò)功能,持續(xù)更新)