Python 並不合適職場程式設計,SPL 才行
職場人員使用 Excel 進行資料處理已經成為家常便飯。不過相信大家一定有過很無助的情況,比如複雜計算、重複計算、自動處理等,再遇上個當機沒儲存,整個人崩潰掉也不是完全不可能。
如果學會了程式語言,這些問題就都不是事了。那麼,該學什麼呢?
無數培訓機構和網上資料都會告訴我們:Python!
Python 程式碼看起來很簡單,只要幾行就能解決許多麻煩的 Excel 計算,看起來真不錯。
但真是如此嗎?作為非專業人員,真能學得會 Python 來協助我們工作嗎?
Python DataFrame
日常職場業務主要是處理表格類資料(用專業的說法是結構化資料),比如這樣的:
表裡除第一行外的每行資料稱為一條記錄,對應了一件事、一個人、一張訂單……,第一行是標題,說明記錄由哪些屬性構成,這些記錄都有相同的屬性,整個表就是這樣一些記錄的集合。
Python 主要是用一個叫 DataFrame 的東西來處理這類表格資料,我們來看看 DataFrame 是怎麼做的。
比如上面的表格,讀入 DataFrame 後是這樣的:
看起來和 Excel 差不多,只是行號是從 0 開始的。
但是,DataFrame 的本質是一個矩陣(大學時代的線性代數還想得起來嗎?),Python 也沒有記錄這樣的概念,它的運算都要繞到矩陣可以執行的方法上才行。
我們來看一些簡單運算。
過濾
過濾是個簡單常見的運算,就是把滿足某一條件的子集取出來,比如還是上面的表格:
問題一:取出 R&D 部門的員工。
Python 程式碼是這樣的:
import pandas as pd data = pd.read_csv('Employees.csv') rd = data.loc[data['DEPT']=='R&D'] print(rd) |
匯入 Pandas 讀取資料 過濾 R&D 部門 檢視 rd 資料 |
執行結果:
程式碼很簡單,結果也沒問題。但是:
1. 用到的函式叫 loc,是 location(定位)的縮寫,完全沒有過濾的意思。事實上,這裡的過濾也是透過定位(location)滿足條件的行的索引來實現的,函式里面的 data[‘DEPT’]==’R&D’會算出一個布林值構成的 Series:
和 data 的索引相同,滿足條件的行為 True 否則為 False
然後 loc 就是根據取值為 True 的行對應的索引再取出 data 中相應的行再得到一個新的 DataFrame,本質上是從矩陣中抽取指定行的運算,用來對付過濾就有點繞。
2. 過濾 DataFrame 並不只可以使用 loc 函式過濾,還可以用 query(…) 等方法,但結果都是定位到矩陣的行列索引,然後按行列索引取資料,大體上是這樣的 matrix.loc[row,col]
無論如何,基本的過濾還算簡單吧,講明白了也能理解。下面我們再嘗試對過濾後的子集做兩個算不上覆雜的運算看看。
修改子集中的資料
問題二:將 R&D 部門員工的工資上調 5%
自然的想法,只要過濾出 R&D 部門員工,然後對這些員工的工資進行修改就可以了。
按照這種邏輯寫出程式碼:
import pandas as pd data = pd.read_csv('Employees.csv') rd = data.loc[data['DEPT']=='R&D'] rd['SALARY']=rd['SALARY']*1.05 print(data) |
匯入 Pandas 讀取資料 過濾 R&D 部門 修改 SALARY |
執行結果:
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation:
rd['SALARY']=rd['SALARY']*1.05
可以看到,不僅觸發了警告,修改值也沒有成功。
這是因為rd = data.loc[data['DEPT']=='R&D']是一個過濾後的矩陣,再使用rd['SALARY']=rd['SALARY']*1.05這個語句修改 SALARY 值的時候,rd['SALARY']又是一個新的矩陣了,因此修改它其實是修改的 rd 這個子矩陣,並沒有修改 data 這個最初的矩陣。
這話說著很繞,聽著也繞。
正確的程式碼怎麼寫呢?
import pandas as pd data = pd.read_csv('Employees.csv') rd_salary = data.loc[data['DEPT']=='R&D','SALARY'] data.loc[data['DEPT']=='R&D','SALARY'] = rd_salary*1.05 print(data) |
找到 R&D 部門的員工工資 擷取 R&D 部門的員工工資並修改
|
執行結果:
這次對了。不可以先取出子集再修改,要對著原矩陣,找到要修改的成員的定位再來修改,即 loc[row=data['DEPT']=='R&D',column='SALARY'],按照行列索引取到要修改的資料,對著這個矩陣賦值。想要上調 5% 還要在此之前先拿到這份資料(rd_salary=…這句)。這種寫法要進行重複的過濾,效率低也就罷了,但實在是太繞了。
子集求交
問題三:找出既是紐約州又是 R&D 部門的員工
這個問題更簡單,只要算出兩個子集做個交集運算就完了。我們看看 Python 是如何處理的:
import pandas as pd data = pd.read_csv('Employees.csv') rd = data[data['DEPT']=='R&D'] ny = data[data['STATE']=='New York'] isect_idx = rd.index.intersection(ny.index) rd_isect_ny = data.loc[isect_idx] print(rd_isect_ny) |
R&D部門員工 紐約州員工 索引求交集 按索引交集擷取資料
|
執行結果:
集合求交是非常基本的運算,很多程式語言都提供了,事實上 python 也提供了(上面有 intersection 函式)。然而, DataFrame 的本質是矩陣,兩個矩陣求交集卻沒有什麼意義,Python 也就沒有提供矩陣求交集的運算。想要做到用兩個 dataframe 表示的集合的交集運算,只能繞道去求兩個矩陣索引的交集,最後再利用索引的交集從原資料上定位擷取,有種捨近求遠的感覺,不按“套路”出牌。
工作中最常用的過濾運算都這麼令人費解,繞的腦袋暈,可以想象其他更復雜的運算,一股酸爽的感覺“悠然而生”。
下面看下稍微複雜一點的分組運算:
分組
分組運算是日常資料處理中最常用的運算了,Python 也提供了豐富的分組運算函式,能夠完成大多數的分組運算,但在理解和使用上並沒有那麼容易。
分組理解
分組就是把一個大集合按某種規則分成一些小集合,結果是個由集合構成的集合,然後再對分組後的集合進行運算,如下圖:
先來看下最常用的分組聚合運算。
問題四:彙總各部門的人數
Python 程式碼:
import pandas as pd data = pd.read_csv('Employees.csv') group = data.groupby("DEPT") dept_num = group.count() print(dept_num) |
按照部門分組 彙總各部門人數 |
執行結果:
結果好像有點尷尬,本來只需要記錄每個分組中的成員數量,只要有一列就行了,為什麼出來這麼多列,它像是對每一列都重複做了同樣的動作,好奇怪。
別急,這個問題 Python 還是可以解決的,只不過不是用 count 函式,而是 size 函式:
import pandas as pd data = pd.read_csv('Employees.csv') group = data.groupby("DEPT") dept_num = group.size() print(dept_num) |
按照部門分組 彙總各部門人數 |
執行結果:
這個結果看起來就正常多了,不過,還是感覺哪裡怪怪的。
是滴,這個結果不再是二維的 DataFrame 了,而是個單維的 Seriese。
count 函式計算的結果之所以奇怪,是因為它是對每一列計數,而 size 函式是檢視各組的大小,但其實我們自然的邏輯還是用 count 來計數,size 很難用自然的邏輯想到(還要上網搜資料)。
如前所述,分組結果應該是集合的集合,我們看看 Python 中的 DataFrame 分組後是什麼樣子呢?把上面程式碼中 data.groupby(“DEPT”) 的結果列印出來看。
import pandas as pd data = pd.read_csv('Employees.csv') group = data.groupby("DEPT") print(group) |
按照部門分組 |
執行結果:
哇,這是個什麼東東?
第一次看到這個東西,直接就蒙圈了,分組的結果不應該是集合的集合嗎,為什麼會是這樣?這對於非專業程式人員來說簡直如同夢魘。
不過上網搜搜還是可以看到它是一個所謂的可迭代物件,迭代以後發現它的每一條都是以分組索引 + DataFrame 構成的,可以使用一些方法看到裡邊的內容,如使用 list(group) 就可以看到分組的結果了。如下圖:
看到上圖以後就會明白,被稱為“物件”的東西里面原來是這樣的。本質上它也確實是個集合的集合(姑且把矩陣理解成集合吧),但它並不能像普通的集合那樣直接取某個成員 (如 group[0]),這在使用上迫使使用者強行記憶這類“物件”的 N 種運算規則,理解不了就只能死記硬背了。
看到這裡,估計已經有很多讀者開始暈菜了,徹底不明白上面這段話是在胡說八道些什麼。嗯,這就對了,因為這才是職場人員的正常狀態。
分組中簡單的聚合運算都如此難以理解,我們再燒燒腦,看下稍微複雜一點的分組後子集合的運算。
分組子集處理
雖然分組後經常用於聚合運算,但有時我們並不關心聚合結果,而是關心分組後的集合本身。比如分組後的集合按某一列排序。
問題五:將各部門員工按照入職時間從早到晚進行排序 。
問題分析:分組後對子集按照入職時間排序即可。
Python 程式碼
import pandas as pd employee = pd.read_csv("Employees.csv") employee['HIREDATE']=pd.to_datetime(employee['HIREDATE']) employee_new = employee.groupby('DEPT',as_index=False).apply(lambda x:x.sort_values('HIREDATE')).reset_index(drop=True) print(employee_new) |
修改入職時間格式
按 DEPT 分組,並對各組按照 HIREDATE 排序,最後重置索引
|
執行結果:
結果沒問題,各個部門員工都按照入職時間從早到晚排序了。但我們觀察下程式碼中最核心的一句employee.groupby('DEPT',as_index=False).apply(lambda x:x.sort_values('HIREDATE')),把這句程式碼抽象一下就是這樣:
df.groupby(c).apply(lambda x:f(x))
df:資料框 DataFrame
groupby:分組函式
c:分組依據的列
以上三個還是比較好理解的,可是 apply 配合 lambda 就十分晦澀難懂了,超出了大多數非專業程式人員理解的範疇,這需要明白所謂“函式語言”的原理才能搞懂(自己去搜尋,俺懶得解釋了)。
如果不使用這“二位”(apply+lambda)呢?也能做,就是會很麻煩。得用 for 迴圈,對每個分組子集分別排序,最後還得把結果合併起來。
import pandas as pd employee = pd.read_csv("Employees.csv") employee['HIREDATE']=pd.to_datetime(employee['HIREDATE']) dept_g = employee.groupby('DEPT',as_index=False) dept_list = [] for index,group in dept_g: group = group.sort_values('HIREDATE') dept_list.append(group) employee_new = pd.concat(dept_list,ignore_index=True) print(employee_new) |
修改入職時間格式 按 DEPT 分組 初始化列表 for迴圈 每個分組排序 排序結果放入列表 合併各組結果 |
執行結果相同,但程式碼複雜了很多,而且執行效率也變低了。你願意用哪一種呢?
Python 對於類似但不完全一樣的資料設計了不同的資料型別,也對應有不同的操作方式,並不能簡單地把對某種資料的知識複製到另一個類似資料上,搞得人暈死。
說了這麼多,總結下來就是一句話:Python 真的挺難懂的,它就不是一個面向非專業選手的東西。具體來說大概就是三點:
1. DataFrame 本質是矩陣
所有的運算都要想辦法按矩陣的方法來計算,經常會很繞。
2. 資料型別多而且運算規則差別很大
Python 中設計了 Series,DataFrame,分組物件等等不同的資料型別,而且不同的資料型別,計算方法也不完全相同,如 DataFrame 可以使用 query 函式過濾,而 Series 不可以,分組物件的本質完全不同於 Series 和 DataFrame,計算方法更是難以捉摸。
3. 知其然而不知其所以然
資料型別過多,計算方法差別又大,無形之中增加了使用者的記憶量,死記硬背的成分更多,想要靈活運用太難了,這就造成了一種奇怪的現象:一個簡單的運算,上網搜尋 Python 程式碼的時間可能比用 excel 計算還要長。
Python 程式碼看起來簡單,但你上了培訓班也大機率學不會,結果只會抄例子。
那麼,是不是就沒有適合職場人員進行日常資料處理的工具了嗎?
還是有的。
esProc SPL
esProc SPL 也是一種程式設計語言,專注於結構化資料計算。SPL 中提供了豐富的基礎計算方法,其概念邏輯也是符合我們的思維習慣的。
1. 序表是記錄的集合
SPL 使用序表承載結構化資料,接近於日常處理的 excel 表。
2. 資料型別少且規則一致
SPL 進行結構化資料處理時幾乎只有集合和記錄兩種資料型別,涉及到的方法也大體一致。
3. 知其然且知其所以然
只要記住兩種資料型別,掌握基本的運演算法則,更復雜的運算就只是簡單運算規則的組合。不熟練時可能寫的程式碼不好看,但不太可能寫不出來,不會出現 Python 那種花費大量時間搜尋程式碼寫法的現象。
下面我們就使用 SPL 來解決上述介紹的問題,大家認真體會下 SPL 是多麼“平易近人”:
序表
esProc SPL 中用於承載二維結構化資料的資料結構是序表,它和 excel 中呈現的結果一致,如下圖:
上表中除了第一行(標題行)外,其他每一行表示一條記錄,而序表就是記錄的集合,相較於 Python 中的 DataFrame 更加直觀。
過濾
SPL 中並不是按照矩陣定位的方式過濾,而是 select(篩選)出滿足條件的記錄。
問題一:檢視 R&D 部門的員工資訊
|
A | B |
1 | =file("Employees.csv").import@tc() | /匯入資料 |
2 | =A1.select(DEPT=="R&D") | /過濾 |
A2 結果:
SPL 過濾後的結果非常好理解,就是原始資料集合的一個子集。
再來看看 SPL 對子集修改和求交集運算
1. 修改子集中的資料
問題二:將 R&D 部門員工的工資上調 5%
|
A | B |
1 | =file("Employees.csv").import@tc() | /匯入資料 |
2 | =A1.select(DEPT=="R&D") | /過濾 |
3 | =A2.run(SALARY=SALARY*1.05) | /修改工資 |
4 | =A1 | /檢視結果 |
A4 結果:
SPL 完全是按照我們正常的思維方式來計算的,過濾出結果,對著結果修改工資,而不像 Python 那麼費勁。
2. 子集求交
問題三:找出既是紐約州又是 R&D 部門的員工
|
A | B |
1 | =file("Employees.csv").import@tc() | /匯入資料 |
2 | =A1.select(DEPT=="R&D") | /R&D部門員工 |
3 | =A1.select(STATE=="New York") | /紐約州員工 |
4 | =A2^A3 | /交集 |
A4 結果:
SPL 中的交集運算就是對著集合求交集,是真正的集合運算,只使用一個簡單的交集運算子“^”即可。易於理解,而且書寫簡單,而不用像 Python 那樣因為無法求矩陣的交集而去求索引的交集,然後再從原資料中擷取。SPL 中的其他集合運算如並集、差集、異或集也都有對應的運算子,使用起來簡單,方便。
分組
分組理解
SPL 的分組運算也是符合自然邏輯的,即分組後結果是集合的集合,顯而易見。
先來看看 SPL 的分組聚合運算。
問題四:彙總各部門的人數
|
A | B |
1 | =file("Employees.csv").import@tc() |
|
2 | =A1.groups(DEPT;count(~):cnt) | /分組 |
A2 結果:
分組聚合的結果,仍然是序表,可以繼續使用序表的方法。並不像 Python 聚合結果成了單維的 Series。
再來看下 SPL 的分組結果
|
A | B |
1 | =file("Employees.csv").import@tc() |
|
2 | =A1.group(DEPT) | /分組 |
A2 結果:
上圖是序表的集合,每個集合是一個部門的成員構成的序表;下圖是點開第一個分組的成員——Administration 部門成員的序表。
這種結果符合我們的正常邏輯,也容易檢視分組的結果,更容易對分組結果進行接下來的運算。
分組子集處理
分組的結果是集合的集合,只要把每個子集進行處理即可。
問題五:將各部門員工按照入職時間從早到晚進行排序
|
A | B |
1 | =file("Employees.csv").import@tc() |
|
2 | =A1.group(DEPT) | /分組 |
3 | =A2.conj(~.sort(HIREDATE)) | /子集排序併合並 |
A3 結果:
由於 SPL 的分組結果還是個集合,因此它可以使用集合的計算方法計算,並不需要強行記憶分組後的計算方法,更不需要使用 apply()+lambda 這種天書般的組合,非常自然的就完成了分組 + 排序 + 合併的工作,簡單的 3 行程式碼,既好寫,又好理解,而且效率很高。
小結
1. Python 進行結構化處理時,本質都是矩陣運算,簡單的集合運算需要繞到矩陣上去運算;esProc SPL 本質是記錄的集合,集合運算簡單便捷。
2. Python 資料型別複雜多樣,運算規則不可預測,往往是知其然而不知其所以然,不太可能舉一反三,寫程式碼記憶的成分更多,想理解其原理太難了;esProc SPL 資料型別少,而且計算規則固定,只需要掌握基本的運算規則就可以舉一反三的完成複雜的運算。
3. 學習 SPL,可以到:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69957599/viewspace-2732078/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Python 並不適合職場程式設計Python程式設計
- 選了風變程式設計,才發現Python並不難學程式設計Python
- (Python程式設計 | 系統程式設計 | 並行系統工具 | 程式退出)Python程式設計並行
- Python並行程式設計Python並行行程程式設計
- python 多cpu並行程式設計Python並行行程程式設計
- 全網最適合入門的物件導向程式設計教程:59 Python並行與併發-並行與併發和執行緒與程序物件程式設計Python並行執行緒
- 三個月不工作,我才轉行做了程式設計師程式設計師
- .NET併發程式設計-資料並行程式設計並行
- 邦芒職場:那些工作後才明白的職場道理
- Python適合網頁程式設計嗎?Python前景如何?Python網頁程式設計
- win10怎麼不合並資料夾_win10設定資料夾從不合並的方法Win10
- 為什麼說:“你不合適學Python?”醍醐灌頂!Python
- 程式設計師如何多執行緒工作,做個職場達人程式設計師執行緒
- 並行程式設計並行行程程式設計
- IT職場:程式設計師如何增加收入?程式設計師
- GPU程式設計(四):並行規約優化GPU程式設計並行優化
- 實現職場轉型,學習風變程式設計Python是優選程式設計Python
- 初學程式設計,Scratch和Python哪個更合適?程式設計Python
- 什麼才算是真正的程式設計能力?程式設計
- 程式設計師才看得明白的面試聖經程式設計師面試
- 併發程式設計和並行程式設計程式設計並行行程
- 併發程式設計-8.並行資料結構和並行Linq程式設計並行資料結構
- python 多執行緒程式設計Python執行緒程式設計
- python程式設計怎麼換行Python程式設計
- Python多執行緒程式設計Python執行緒程式設計
- 程式設計師職場之路,如何提升技術能力?程式設計師
- .NET併發程式設計-任務函式並行程式設計函式並行
- Fira Code:適合程式設計師的程式設計字型程式設計師
- Python多程序中並行程式設計與程序池Python並行行程程式設計
- Python語言初學者?風變程式設計更適合Python程式設計
- 怎樣才算得上合格的程式設計師程式設計師
- Python並行程式設計(七):多程式的基本使用和與多執行緒的差異Python並行行程程式設計執行緒
- 使用 VS Code 進行 Python 程式設計Python程式設計
- Python多執行緒程式設計(二)Python執行緒程式設計
- 使用Python進行併發程式設計Python程式設計
- C#並行,多執行緒程式設計並行集合和PLINQ的例項講解並行執行緒程式設計
- 獻給剛入職場的草根java程式設計師Java程式設計師
- 逆襲職場,有風變程式設計就夠了程式設計