python算不算编程_Python 并不适合职场编程
職場人員使用 Excel 進行數據處理已經成為家常便飯。不過相信大家一定有過很無助的情況,比如復雜計算、重復計算、自動處理等,再遇上個死機沒保存,整個人崩潰掉也不是完全不可能。
如果學會了程序語言,這些問題就都不是事了。那么,該學什么呢?
無數培訓機構和網上資料都會告訴我們:Python!
Python 代碼看起來很簡單,只要幾行就能解決許多麻煩的 Excel 計算,看起來真不錯。
但真是如此嗎?作為非專業人員,真能學得會 Python 來協助我們工作嗎?
Python DataFrame
日常職場業務主要是處理表格類數據(用專業的說法是結構化數據),比如這樣的:
表里除第一行外的每行數據稱為一條記錄,對應了一件事、一個人、一張訂單……,第一行是標題,說明記錄由哪些屬性構成,這些記錄都有相同的屬性,整個表就是這樣一些記錄的集合。
Python 主要是用一個叫 DataFrame 的東西來處理這類表格數據,我們來看看 DataFrame 是怎么做的。
比如上面的表格,讀入 DataFrame 后是這樣的:
看起來和 Excel 差不多,只是行號是從 0 開始的。
但是,DataFrame 的本質是一個矩陣(大學時代的線性代數還想得起來嗎?),Python 也沒有記錄這樣的概念,它的運算都要繞到矩陣可以執行的方法上才行。
我們來看一些簡單運算。
過濾
過濾是個簡單常見的運算,就是把滿足某一條件的子集取出來,比如還是上面的表格:
問題一:取出 R&D 部門的員工。
Python 代碼是這樣的:
import pandas as ? pd? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?導入 Pandas
data = ? pd.read_csv('Employees.csv')? ? ? ?讀取數據
rd = data.loc[data['DEPT']=='R&D']? ? ? ? ? ? ??過濾 R&D 部門
print(rd)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?查看 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? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??導入 Pandas
data = pd.read_csv('Employees.csv')? ? ? ? ? ? ?讀取數據
rd = ? data.loc[data['DEPT']=='R&D']? ? ? ? ? ? ? ??過濾 R&D 部門
rd['SALARY']=rd['SALARY']*1.05? ? ? ? ? ? ? ? ? ? ?修改 SALARY
print(data)
運行結果:
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: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
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']? ? ? ? ? ? ? ? ?找到 R&D 部門的員工工資
data.loc[data['DEPT']=='R&D','SALARY'] ? = rd_salary*1.05? ? ? ?截取 R&D 部門的員工工資并修改
print(data)
運行結果:
這次對了。不可以先取出子集再修改,要對著原矩陣,找到要修改的成員的定位再來修改,即 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']? ? ? ? ? ? ? ? ? ? ? ? ?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)
運行結果:
集合求交是非常基本的運算,很多程序語言都提供了,事實上 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)? ? ? ? ? ??按 DEPT 分組,并對各組按照 HIREDATE 排序,最后重置索引
print(employee_new)
運行結果:
結果沒問題,各個部門員工都按照入職時間從早到晚排序了。但我們觀察下代碼中最核心的一句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 分組
dept_list = []? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??初始化列表
for index,group in dept_g:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?for循環
group = ? group.sort_values('HIREDATE')? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?每個分組排序
dept_list.append(group)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?排序結果放入列表
employee_new = pd.concat(dept_list,ignore_index=True)? ? ? ? ? ??合并各組結果
print(employee_new)
運行結果相同,但代碼復雜了很多,而且運行效率也變低了。你愿意用哪一種呢?
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,可以到:
總結
以上是生活随笔為你收集整理的python算不算编程_Python 并不适合职场编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sql自动生成工具_可自动生成代码,5款
- 下一篇: 查看cpu使用率_腾讯游戏开发工程师:L