早下班系列:輕松玩轉(zhuǎn)Excel行列轉(zhuǎn)換

下面這種交叉式的Excel表是很常見的格式,用來填寫和查看都比較方便:

但是,如果想做進(jìn)一步的統(tǒng)計(jì)分析,這種格式就不方便了,需要行列轉(zhuǎn)換,變成如下格式的明細(xì)表:

顯然,手工操作會(huì)非常麻煩,若數(shù)據(jù)量小還可以,數(shù)據(jù)量大了會(huì)耗費(fèi)大量時(shí)間,簡直就是災(zāi)難。
Excel也可以通過數(shù)據(jù)透視表支持行列轉(zhuǎn)換功能,效果如下圖:

但這并不是我們想要的格式。
看來只能寫個(gè)程序來解決了,思路也很簡單:
- 加載excel文件,裝載需要的sheet工作表。
- 讀取賬套名所在的行,將其轉(zhuǎn)換成字符串?dāng)?shù)組。
- 讀取科目編碼所在列,將其轉(zhuǎn)換成字符串?dāng)?shù)組。
- 按科目編碼分組,與賬套名數(shù)組構(gòu)造一張表。
- 根據(jù)賬套名對(duì)應(yīng)的數(shù)據(jù),遍歷所有的明細(xì)值填充到相應(yīng)的表中。
- 這樣就構(gòu)造出對(duì)應(yīng)的明細(xì)表來。
如果用Java來實(shí)現(xiàn),初步估計(jì)代碼量也不會(huì)少于200行,若需要結(jié)果輸出成excel文件則開發(fā)工作量會(huì)更多。Excel自己雖然提供了VBA,但那個(gè)麻煩度誰用誰知道,不提也罷。其它的語言呢?傳說python有處理行列轉(zhuǎn)換的功能(pandas包里有pivot功能),代碼量相對(duì)于java會(huì)少很多, 我們來試一下:
- import pandas as pd
- import numpy as np
- df = pd.read_excel(“D:\\excel\\pandas.xlsx”, 0, 3)
- cols = df.columns.values.tolist() #獲取數(shù)據(jù)頭信息
- #移去前兩列,只保留需要行列轉(zhuǎn)換的列
- cols.remove(‘科目編碼’)
- cols.remove(‘科目明細(xì)’)
- #構(gòu)造一個(gè)list.
- frames=[]
- for col in cols:
- df1 = df.pivot_table(index = [‘科目編碼’,’科目明細(xì)’], values = [col])
- df1.rename(columns={col: ‘數(shù)值’}, inplace=True)
- df1[3]=col
- #轉(zhuǎn)換后的數(shù)據(jù)追加到frames中.
- frames.append(df1)
- # concat將相同字段的表首尾相接
- result=pd.concat(frames)
- result.rename(columns={3: ‘帳套名’}, inplace=True)
- result.to_excel(‘D:\\excel\\pandas_n.xlsx’, sheet_name=’科目明細(xì)’)
嗯,還不錯(cuò),果然比較簡潔!這是Python生成的excel文件:

不過,這里有點(diǎn)小問題,這個(gè)excel格式有點(diǎn)特殊,想用Python的 pivot,我們要將“科目編碼”,“科目明細(xì)”移到與轉(zhuǎn)換列標(biāo)題所在同一行上,變成下面的樣子。否則在代碼上就得特殊 “照顧”,反正只有一行,手工做一下就算了,比寫代碼省事。

無論如何,python的這個(gè)細(xì)節(jié)處理的小”瑕疵”并不影響其方便性。python確實(shí)名不虛傳,雖然使用了循環(huán),但整個(gè)代碼也就只有10來行的樣子。
還能更簡單嗎?
嘿嘿,能!
我們來看集算器的代碼:
| A | B | |
| 1 | =file(“D:/excel/明細(xì).xlsx”).importxls@t(;1,3:40) | //讀入excel文件 |
| 2 | >A1.delete(A1.select(_1==”科目編碼”)) | //清除首列為”科目編碼”所在的行 |
| 3 | >A1.rename(_1:科目編碼,_2:科目明細(xì)) | //更換列1名稱為科目編碼,列2名稱為科目明細(xì) |
| 4 | =A1.fname().to(3,).concat(“,”) | //將從第三列的列名連成字符串,用,分開 |
| 5 | =A1.pivot@r(科目編碼,科目明細(xì);賬套名,數(shù)值;${A4}) | //用pivot函數(shù)進(jìn)行行列轉(zhuǎn)換 |
| 6 | =file(“D:/excel/明細(xì)2.xlsx”).exportxls@t(A5;”科目明細(xì)”) | //將整理好的數(shù)據(jù)另存儲(chǔ)為xlsx文件 |
代碼很簡單,我們把每一步的中間結(jié)果列出來看看:
A1:加載excel文件工作表1,提取指定范圍的數(shù)據(jù)(從3行到40行),其中選項(xiàng)@ t表示首行為標(biāo)題,載入數(shù)據(jù),生成表格如下:

A2:刪除非數(shù)據(jù)行

A3:更換列名稱

A4:把從第三列開始的列名稱連成字符串,用“,”分開

A5:pivot函數(shù)將行列數(shù)據(jù)進(jìn)行轉(zhuǎn)換,把A4中對(duì)應(yīng)的列數(shù)據(jù)置放到“數(shù)值”列

A6:將整理好的數(shù)據(jù)另存儲(chǔ)為xls文件

集算器腳本只6行,而且木有啥循環(huán)、判斷之類的玩意兒,也不像Python那樣要先手工倒騰一下,就把這看似有點(diǎn)“亂”的數(shù)據(jù)表格處理好了。相比之下,Python采用列優(yōu)先轉(zhuǎn)換多次循環(huán) “N”字方式,集算器則用行優(yōu)先一次性處理,在處理數(shù)據(jù)上,集算器對(duì)細(xì)節(jié)處理及使用習(xí)慣更專業(yè)。而且集算器的開發(fā)環(huán)境也容易調(diào)試,可以看到每一步運(yùn)算的中間結(jié)果,方便挑出錯(cuò)誤,開發(fā)更為便捷。在這種常規(guī)數(shù)據(jù)處理的任務(wù)中,集算器要比Python更為優(yōu)越。
就這個(gè)問題,關(guān)于 python與集算器的差異,再說說自己的一點(diǎn)體會(huì):
1.多列轉(zhuǎn)換:
對(duì)于需要多列行列轉(zhuǎn)換并匯集成“長”列的場(chǎng)景時(shí),python需要將每個(gè)數(shù)據(jù)列構(gòu)造成數(shù)組,并增加一列記錄當(dāng)前列名,再追加到一個(gè)大的列表中,***合并,合并中去掉非***數(shù)組中的title;
集算器就容易些,它直接把想要轉(zhuǎn)換的列匯集在一塊就行。相對(duì)于python的繁瑣,集算器至少能省幾個(gè)腦細(xì)胞。
2.名稱更改:
python對(duì)于需要轉(zhuǎn)換列的名稱不能更改,如cols[0]=’天津’,此時(shí)python找不到修改前的關(guān)鍵字,“哪個(gè)朋友挖的坑,別以為我發(fā)現(xiàn)不了”,欺負(fù)大爺眼花,給報(bào)個(gè)異常行不?
但對(duì)應(yīng)的集算器來說則很方便,如:>A1.rename(_1:科目編碼,_2:科目明細(xì),4成都: 成都)
3.標(biāo)題空值問題:
Python讀取excel表中的轉(zhuǎn)換行標(biāo)題時(shí),前面兩列為空(對(duì)應(yīng)原來的excel中的“科目編碼,科目明細(xì)”),此時(shí)標(biāo)題cols中的空值就沒有了,這個(gè)“坑”有點(diǎn)隱蔽啊,我真沒有發(fā)現(xiàn),把其中的兩列弄丟了,真有點(diǎn)丟臉 ;
但集算器能識(shí)別出來,會(huì)自動(dòng)加上對(duì)應(yīng)的標(biāo)識(shí)_1、_2,這樣處理數(shù)據(jù)時(shí),就能找到其中對(duì)應(yīng)的兩列。
4.網(wǎng)格式編程
集算器使用網(wǎng)格A1這種格式,它自動(dòng)與所在位置的對(duì)象關(guān)聯(lián)起來,這點(diǎn)非常方便,感覺很有特色;Python就只能望洋興嘆了。























