簡(jiǎn)明python開發(fā)教程(3):用Pandas進(jìn)行數(shù)據(jù)處理

Python有很多典型應(yīng)用蔬崩,我們?nèi)粘9ぷ鹘?jīng)常遇到一些數(shù)據(jù)分析相關(guān)的問題恶座,傳統(tǒng)的方式使用Excel進(jìn)行處理,耗時(shí)長(zhǎng)沥阳,特定是一些重復(fù)性的例行工作跨琳。
Python提供很多強(qiáng)大的數(shù)據(jù)分析相關(guān)的庫,如numpy桐罕、pandas等脉让。其實(shí)我們簡(jiǎn)單的日常使用pandas就夠了。

Pandas介紹

Pandas是一個(gè)強(qiáng)大的數(shù)據(jù)分析第三方庫功炮,Anaconda已經(jīng)自動(dòng)攜帶溅潜,無需安裝,只需import導(dǎo)入即可使用死宣。一般用以下語法:

import pandas as pd

Pandas提供兩種常用的數(shù)據(jù)結(jié)構(gòu):Series和DataFrame伟恶。
其中Series可以看作一行或一列數(shù)據(jù),DataFrame是一個(gè)二維表格數(shù)據(jù)毅该,和excel表格類似博秫,有行索引和列索引潦牛。
Pandas提供很多便捷的函數(shù),用來創(chuàng)建挡育、處理巴碗、保存DataFrame,任何你想到的遇到的問題都可以百度解決即寒。
建議通過十分鐘入門Pandas進(jìn)行快速了解橡淆,當(dāng)然有作者翻譯成了中文版,自己搜索母赵。

下面通過一個(gè)實(shí)際案例詳細(xì)了解Pandas進(jìn)行數(shù)據(jù)分析處理的過程逸爵。

問題需求

在日常工作中,我們需要定期從某個(gè)網(wǎng)站下載數(shù)據(jù)表格凹嘲。

image.png

我們需要將多份表格中的 “廠家-設(shè)備類型” Sheet數(shù)據(jù)合并师倔、處理、匯總周蹭,該sheet的數(shù)據(jù)格式如下:

image.png

我們期望按照廠家趋艘、設(shè)備類型匯報(bào)告警量,由于部分廠家凶朗、設(shè)備類型可能缺失導(dǎo)致無法對(duì)齊瓷胧,無法自動(dòng)相加,人工匯總困難棚愤,而python則非常簡(jiǎn)單搓萧。

代碼實(shí)現(xiàn)

首先使用pandas讀取兩個(gè)excel,分別df1和df2,然后使用pandas自帶的合并函數(shù)實(shí)現(xiàn)匯總遇八,自動(dòng)對(duì)齊矛绘、處理缺失值。

pandas讀取excel

import pandas as pd
#定義待讀取的文件名
filename1 = '省監(jiān)控-核心網(wǎng)-全量告警_38AB1AE7.xlsx'
filename2 = '省監(jiān)控-核心網(wǎng)-全量告警_964C9DCF.xlsx'
#使用pandas的函數(shù)讀取excel刃永,當(dāng)前目錄,直接寫文件名即可羊精,可以有很多參數(shù)斯够,這里指定所需sheet
df1 = pd.read_excel(filename1,sheetname='廠家-設(shè)備類型')
df2 = pd.read_excel(filename2,sheetname='廠家-設(shè)備類型')

以上代碼可以讀取兩個(gè)excel文件⌒酰可以通過pandas.head() 可以顯示前幾行數(shù)據(jù)读规,
可以快速查看DataFrame的格式,如列名燃少,數(shù)據(jù)格式等束亏,判斷是否正確載入數(shù)據(jù)。

image.png

代碼的關(guān)鍵是掌握pandas.read_excel()函數(shù)阵具。

pandas.read_excel(io, sheet_name=0, header=0, skiprows=None, skip_footer=0, index_col=None, names=None, usecols=None, parse_dates=False, date_parser=None, na_values=None, thousands=None, convert_float=True, converters=None, dtype=None, true_values=None, false_values=None, engine=None, squeeze=False, **kwds)

其中io或者filename就是待讀取的文件路徑碍遍,可以是相對(duì)路徑或絕對(duì)路徑定铜。sheetname指定sheet,還有很多參數(shù)可以個(gè)性化讀取文件怕敬,這里無需使用揣炕。
同時(shí)pandas還提供了大量其他read類函數(shù),可以讀取其他類型文件东跪,如sql畸陡、csv等等。

pandas按照特定列合并處理

那么這兩個(gè)df如何按照廠家和設(shè)備類型對(duì)告警量進(jìn)行累加呢虽填,也就是按照“廠家”和“設(shè)備類型”兩列進(jìn)行處理丁恭。
有一個(gè)最直觀的辦法就是循環(huán),通過遍歷所有廠家和設(shè)備類型斋日,然后講兩個(gè)df對(duì)應(yīng)的值求和,涩惑,雖然想法很簡(jiǎn)單,但是實(shí)現(xiàn)還是很復(fù)雜桑驱。
首先的知道兩個(gè)文件的最大廠家竭恬、設(shè)備類型集合,然后再遍歷熬的。

#獲取兩個(gè)文件的最大廠家痊硕、設(shè)備類型集合
cjlx1 = [tuple(df1.loc[i][['廠家','設(shè)備類型']]) for i in df1.index]
cjlx2 = [tuple(df2.loc[i][['廠家','設(shè)備類型']]) for i in df2.index]
cjlx = set(cjlx1+cjlx2)
#遍歷最大設(shè)備類型集合,求得合并告警量
rows = [] #輸出列表集合押框,可以轉(zhuǎn)換為DataFrame
for i in cjlx:  #遍歷最大(廠家岔绸、類型)集合
    cj = i[0]   #獲取廠家名稱
    lx = i[1]   #獲取設(shè)備類型
    if i in cjlx1:  #如果該(廠家,類型)對(duì)在文件1中橡伞,取得對(duì)應(yīng)告警量,否則告警量為0
        num1 = df1[(df1['廠家'] == cj) & (df1['設(shè)備類型']==lx)]['告警量'].iloc[0]
    else:
        num1 = 0
    if i in cjlx2:
        num2 = df2[(df2['廠家'] == cj) & (df2['設(shè)備類型']==lx)]['告警量'].iloc[0]
    else:
        num2 = 0   
    num = num1 + num2    #兩個(gè)告警量相加
    row = [cj,lx,num]   #生成新的一行數(shù)據(jù)
    rows.append(row)    #追加到輸出列表
data = pd.DataFrame(rows,columns = ['廠家','設(shè)備類型','告警量'])     #轉(zhuǎn)換為DataFrame

可以看到最新的data已經(jīng)是匯總后的數(shù)據(jù)盒揉,一個(gè)excel有71行數(shù)據(jù),一個(gè)78行數(shù)據(jù)兑徘,合并后數(shù)據(jù)80行刚盈。

In[112]: len(df1),len(df2),len(data)  #In表示輸入,冒號(hào)后才是真實(shí)代碼
Out[112]: (71, 78, 80)
In[113]:data.head()
Out[113]: 
      廠家     設(shè)備類型   告警量
0  CISCO      交換機(jī)  2021
1     東信     HOST    56
2     東信      交換機(jī)    16
3     中興     HOST   182
4    愛立信  HSS_SLF     2

上面代碼涉及了Python的常用語法和Pandas的基本操作挂脑,可以簡(jiǎn)單分享下藕漱,更多內(nèi)容需要自己查閱。

  • python list的基本操作
    創(chuàng)建[1,2,3]崭闲,append肋联,list1+list2,列表表達(dá)式創(chuàng)建新list [ i for i in x] 可以對(duì)i進(jìn)行操作變換刁俭,可以加條件過濾橄仍,如
In[114]:[i*2 for i in range(5) if i >2]  #In表示輸入,冒號(hào)后才是真實(shí)代碼
Out[114]: [6, 8]
In[115]:[i*2 for i in range(5) ]
Out[115]: [0, 2, 4, 6, 8]

還有Python的集合set、元組tuple的基礎(chǔ)操作侮繁,建議自學(xué)虑粥。

  • for if基本控制流
    通過for循環(huán)遍歷,用in關(guān)鍵字實(shí)現(xiàn)遍歷鼎天,if...else實(shí)現(xiàn)條件判斷舀奶,最簡(jiǎn)單示例如下:
for i in range(5):
    print(i)
    if i>2:
        print('我是if為真的結(jié)果:',i*2)
        
0
1
2
3
我是if為真的結(jié)果: 6
4
我是if為真的結(jié)果: 8
  • Pandas的基本操作
    DataFrame可以遍歷索引index,可以快速選取某些值斋射。
    .loc 可以獲取某個(gè)位置值育勺,df[bool] 可以快速選擇bool為真的那些行數(shù)據(jù)。
    如何快速選取某些行或某些列罗岖。如
In[118]:df1.loc[0][['廠家','設(shè)備類型']]
Out[118]: 
廠家      CISCO
設(shè)備類型     HOST
Name: 0, dtype: object
In[119]:df1.loc[0]['廠家']
Out[119]: 'CISCO'
In[121]: bl = df1['廠家'] == cj
In[122]: len(bl),bl[0]  #得到長(zhǎng)度為71的bool值list
Out[122]: (71, False)
In[123]:df1[bl]  #獲取bl為真的那些行數(shù)據(jù)
Out[123]: 
     廠家        設(shè)備類型     告警量
7   愛立信         BSC  254984
8   愛立信          CG     175
9   愛立信      HLR_FE    4100

更多內(nèi)容關(guān)注Pandas官網(wǎng)或者其他相關(guān)教程涧至。

Pandas優(yōu)化處理

Pandas是一個(gè)非常優(yōu)秀的數(shù)據(jù)處理庫,實(shí)現(xiàn)上述功能肯定不用這么復(fù)雜桑包,有一些自帶的函數(shù)可以快速合并南蓬、規(guī)整兩個(gè)DataFrame。主要有append哑了、mergeconcat等操作赘方。

  • append
    可以在df后添加行或者另一個(gè)df,有一些限制弱左。然后對(duì)df3進(jìn)行分組groupby窄陡,對(duì)告警量列進(jìn)行求和即可(分組建會(huì)作為index,需要提取出來作為新的一列):
In[125]:df3 = df1.append(df2)
In[125]:len(df1),len(df2),len(df3)  #df3的行數(shù)是df1 和df2的和
Out[125]: (71, 78, 149)
  • merge
    通過一個(gè)或多個(gè)鍵(列名)將行連接起來拆火。多種連接方式跳夭,左連接,右連接等们镜。
    其中on表示用哪些鍵連接起來币叹,how表示連接方式。
In[135]:df4 = pd.merge(df1,df2,on=['廠家','設(shè)備類型'],how = 'outer')
In[136]:df1.shape,df2.shape,df4.shape,  #可以發(fā)現(xiàn)df4是80*4,其中80行已經(jīng)是最大集合模狭,是我們想要的結(jié)果颈抚,
Out[136]: ((71, 3), (78, 3), (80, 4))
In[137]:df4.head()
Out[137]: 
        廠家  設(shè)備類型   告警量_x  告警量_y
0    CISCO  HOST    16.0    1.0
1    CISCO   交換機(jī)  1484.0  537.0
2    CISCO   路由器    93.0  152.0
3      IBM  HOST   702.0  745.0
4  JUNIPER   路由器     7.0    6.0

其中告警量_x,告警量_y是原先兩個(gè)告警量,重名會(huì)自動(dòng)增加_x和_y胞皱,以便區(qū)分邪意。
接下來只需將這兩列相加即可。

df4['告警量'] = df4['告警量_x'] + df4['告警量_y']

這樣直接相加會(huì)有問題反砌,存在nan值問題。

image.png

因此我們需要將nan值替換為0萌朱,再求和宴树。修改后代碼如下

#使用pd.merge()  快速連接
data = pd.merge(df1,df2,on=['廠家','設(shè)備類型'],how = 'outer') #連接兩個(gè)df
data = data.fillna(0)   #用0替換nan值
data['告警量'] = data['告警量_x'] + data['告警量_y'] #兩個(gè)告警量相加,得到新的一列告警量
data = data[['廠家','設(shè)備類型','告警量']]    #只選取我們想要的三列

以上生成的data和一開始循環(huán)遍歷結(jié)果一樣晶疼,但是代碼非常精簡(jiǎn)酒贬。同樣concat可以實(shí)現(xiàn)類似的連接又憨,然后再進(jìn)行處理。請(qǐng)自行實(shí)現(xiàn)锭吨。

Pandas文件保存

Pandas可以非常方便將文件保存為各種格式蠢莺,如df.to_csv()df.to_excel()零如。建議直接使用to_csv躏将,簡(jiǎn)單快速。

data.to_csv('out.csv',encoding= 'gbk',index = False)
ls
 C:\Users\zhuf0\Documents\repository\pythondemo 的目錄

2018/04/04  08:44    <DIR>          .
2018/04/04  08:44    <DIR>          ..
2018/04/04  08:44               521 out.csv

可以看到本地目錄已經(jīng)有out.csv考蕾。其中encoding設(shè)置了編碼方式祸憋、index可以設(shè)置是否保存索引。還有更多參數(shù)關(guān)注官網(wǎng)及其他教程肖卧。

代碼優(yōu)化

上面已經(jīng)實(shí)現(xiàn)了核心功能蚯窥,下面將代碼優(yōu)化一下,以便更好用塞帐。

優(yōu)化1 基本功能函數(shù)化

編寫一個(gè)函數(shù)拦赠,輸入兩個(gè)df,返回求和后df葵姥。

def get_df_sums(df1,df2):
    if df1.empty:   #檢查其中一個(gè)df為空
        return df2
    elif df2.empty:
        return df1
    else:
        data = pd.merge(df1,df2,on=['廠家','設(shè)備類型'],how = 'outer') #連接兩個(gè)df
        data = data.fillna(0)   #用0替換nan值
        data['告警量'] = data['告警量_x'] + data['告警量_y'] #兩個(gè)告警量相加荷鼠,得到新的一列告警量
        data = data[['廠家','設(shè)備類型','告警量']]    #只選取我們想要的三列
    return data

優(yōu)化2 自動(dòng)讀取多個(gè)文件

一般情況下,待匯總的文件不止兩個(gè)牌里,我們可以使用Python腳本自動(dòng)讀取某個(gè)特定路徑下所有文件颊咬。

import os
path = r"C:\Users\zhuf0\Documents\repository\pythondemo"
out = pd.DataFrame()
for filename in os.listdir(path):#遍歷指定路徑的所有文件名
    if '省監(jiān)控-核心網(wǎng)-全量告警' in filename: #選擇指定文件待讀取
        filename = path+"\\"+filename   #獲取絕對(duì)路徑
        df1 = pd.read_excel(filename,sheetname='廠家-設(shè)備類型')   #讀取該sheet
        out = get_df_sums(out,df1)  #和之前的out累積求和,類似 sum=sum+i

只需要將待匯總的文件放到指定目錄即可牡辽,輸出out.csv喳篇。

優(yōu)化3 排序后保存

Pandas 有很強(qiáng)大的排序功能,可以按照多列排序态辛。sort_values
如按照告警量排序:

In[164]out = out.sort_values(by = '告警量',ascending = False)  #按照告警量降序排列
In[164]:out.head()
Out[164]: 
     廠家        設(shè)備類型       告警量
7   愛立信         BSC  481307.0
65   中興         MME  163725.0
14  愛立信         MME   99553.0
13  愛立信         MGW   37488.0
16  愛立信  MSC_Server   24683.0

留個(gè)問題麸澜,能否分組排序,按廠家分組奏黑,如愛立信炊邦,然后組內(nèi)告警量降序排列。廠家的排序方式按照該廠家的最大告警量排序熟史,而不是廠家的名稱馁害。如愛立信后是中興。

最終代碼

為了更像一個(gè)腳本蹂匹,也為了后續(xù)擴(kuò)展復(fù)用碘菜,最終優(yōu)化后腳本為,保存為pandas_demo.py文件:

import pandas as pd
import os
#給定兩個(gè)df,返回求和后結(jié)果
def get_df_sums(df1,df2):
    if df1.empty:   #檢查其中一個(gè)df為空
        return df2
    elif df2.empty:
        return df1
    else:
        data = pd.merge(df1,df2,on=['廠家','設(shè)備類型'],how = 'outer') #連接兩個(gè)df
        data = data.fillna(0)   #用0替換nan值
        data['告警量'] = data['告警量_x'] + data['告警量_y'] #兩個(gè)告警量相加,得到新的一列告警量
        data = data[['廠家','設(shè)備類型','告警量']]    #只選取我們想要的三列
    return data
#給定路徑path忍啸,求和指定格式全部文件
def get_all_path(path):
    out = pd.DataFrame()
    for filename in os.listdir(path):#遍歷指定路徑的所有文件名
        if '省監(jiān)控-核心網(wǎng)-全量告警' in filename: #選擇指定文件待讀取
            filename = path+"\\"+filename   #獲取絕對(duì)路徑
            df1 = pd.read_excel(filename,sheetname='廠家-設(shè)備類型')   #讀取該sheet
            out = get_df_sums(out,df1)  #和之前的out累積求和仰坦,類似 sum=sum+i
    out = out.sort_values(by = '告警量',ascending = False)
    return out

#作為主程序運(yùn)行
if __name__ =='__main__':
    path = r"C:\Users\zhuf0\Documents\repository\pythondemo"
    out = get_all_path(path)
    out.to_csv('out.csv',encoding= 'gbk',index = False) #保存

腳本使用

只要我們將待處理的文件放到該目錄,然后命令行運(yùn)行該腳本即可计雌。
執(zhí)行 python pandas_demo.py 沒有任何提示悄晃,說明成功。

image.png

打開out.csv查看

image.png

同樣我們可以進(jìn)一步優(yōu)化將路徑作為參數(shù)提供凿滤,指定輸出目錄妈橄,增加一些提示性輸出,增加腳本穩(wěn)健性鸭巴。
Python數(shù)據(jù)分析功能非常強(qiáng)大眷细,網(wǎng)上也有很多很好的項(xiàng)目和教程,大家可以結(jié)合實(shí)際工作問題鹃祖,選擇合適項(xiàng)目入門學(xué)習(xí)溪椎。
時(shí)間優(yōu)先,沒有太多排版恬口。如有錯(cuò)誤請(qǐng)及時(shí)反饋校读。
下一篇我們學(xué)習(xí)用Python自動(dòng)運(yùn)維——簡(jiǎn)明Python開發(fā)教程(4):網(wǎng)絡(luò)自動(dòng)化運(yùn)維的曙光

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市祖能,隨后出現(xiàn)的幾起案子歉秫,更是在濱河造成了極大的恐慌,老刑警劉巖养铸,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雁芙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡钞螟,警方通過查閱死者的電腦和手機(jī)兔甘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鳞滨,“玉大人洞焙,你說我怎么就攤上這事≌玻” “怎么了澡匪?”我有些...
    開封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)褒链。 經(jīng)常有香客問我唁情,道長(zhǎng),這世上最難降的妖魔是什么甫匹? 我笑而不...
    開封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任荠瘪,我火速辦了婚禮夯巷,結(jié)果婚禮上赛惩,老公的妹妹穿的比我還像新娘哀墓。我一直安慰自己,他們只是感情好喷兼,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開白布篮绰。 她就那樣靜靜地躺著,像睡著了一般季惯。 火紅的嫁衣襯著肌膚如雪吠各。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天勉抓,我揣著相機(jī)與錄音贾漏,去河邊找鬼。 笑死藕筋,一個(gè)胖子當(dāng)著我的面吹牛纵散,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播隐圾,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼伍掀,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了暇藏?” 一聲冷哼從身側(cè)響起蜜笤,我...
    開封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎盐碱,沒想到半個(gè)月后把兔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瓮顽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年县好,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片趣倾。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡聘惦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出儒恋,到底是詐尸還是另有隱情善绎,我是刑警寧澤,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布诫尽,位于F島的核電站禀酱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏牧嫉。R本人自食惡果不足惜剂跟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一减途、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧曹洽,春花似錦鳍置、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至偷崩,卻和暖如春辟拷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背阐斜。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工衫冻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谒出。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓隅俘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親到推。 傳聞我的和親對(duì)象是個(gè)殘疾皇子考赛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容