引言
這是Python數據分析實戰基礎的第三篇內容,主要對前兩篇進行補充,把實際數據清洗場景下常用但零散的方法,按增
、刪
、查
、分
四板斧的邏輯進行歸類,以減少記憶成本,提升學習和使用效率。
數據集
一級流量
流量級別 | 投放地區 | 訪客數 | 支付轉化率 | 客單價 | 支付金額 |
---|---|---|---|---|---|
一級 | A區 | 44,300 | 11.78% | 58.79 | 306,887.83 |
一級 | B區 | 30,612 | 13.85% | 86.64 | 367,338.10 |
一級 | C區 | 18,389 | 2.50% | 0.28 | 129.58 |
一級 | D區 | 4,509 | 10.73% | 64.12 | 31,035.14 |
一級 | E區 | 3,769 | 5.73% | 92.91 | 20,068.20 |
一級 | F區 | 2,424 | 22.07% | 89.33 | 47,791.60 |
一級 | G區 | 2,412 | 8.21% | 56.04 | 11,096.42 |
二級流量
流量級別 | 投放地區 | 訪客數 | 支付轉化率 | 客單價 | 支付金額 |
---|---|---|---|---|---|
二級 | A區 | 29,111 | 10.66% | 87.4 | 271,189.23 |
二級 | B區 | 17,165 | 22.71% | 91.22 | 355,662.39 |
二級 | C區 | 8,870 | 0.78% | 44.52 | 3,072.00 |
三級流量
流量級別 | 投放地區 | 訪客數 | 支付轉化率 | 客單價 | 支付金額 |
---|---|---|---|---|---|
三級 | A區 | 45,059 | 13.66% | 90.11 | 554,561.22 |
三級 | B區 | 2,133 | 10.83% | 74.48 | 17,204.50 |
三級 | C區 | 899 | 9.90% | 92.99 | 8,276.50 |
三級 | D區 | 31 | 0.00% | ||
三級 | E區 | 17 | 0.00% |
上述三個級別數據在同一個excel中不同Sheet中。
首先,導入案例數據集。因爲案例數據存放在同一個Excel表的不同Sheet
下,我們需要指定sheetname分別讀取:
下面開始清洗的正餐。
1 增——拓展數據維度
1. 縱向合併
這三個sheet的數據,維度完全一致(每列數據都是一樣),縱向合併起來分析十分方便。說到縱向合併,concat大佬不請自來,他的招式簡單明瞭 pd.concat([表1,表2,表3])
,對於列字段統一的數據,我們只需把表依次傳入參數:
concat大佬繼續說到:其實把我參數axis設置成1就可以橫向合併
說時遲那時快,我一個箭步衝上去捂住他的嘴巴,牛逼的人做好一件事就夠了,橫向的就交給merge
吧~!
溫馨提示
:pandas中很多函數功能十分強大,能夠實現多種功能,但對於萌新來說,過多甚至交叉的功能往往會造成懵B的狀態,所以這裏一種功能先只用一種方式來實現。
2. 橫向合併
橫向合併涉及到連接問題,爲方便理解,我們構造一些更有代表性的數據集練手:
h1 = pd.DataFrame({'語文':[93,80,85,76,58],'數學':[87,99,95,85,70],'英語':[80,85,97,65,88]},index=['韓梅梅','李雷','李華','王明','鐵蛋'])
h1
h2 = pd.DataFrame({'籃球':[93,80,85,76],'舞蹈':[87,99,95,85]},index=['李華','王明','鐵蛋','劉強'])
h2
兩個DataFrame是兩張成績表,h1是5位同學的數學、英語、語文成績,h2是4位同學的籃球和舞蹈成績,現在想找到併合並兩張表同時出現的同學及其成績
,可以用merge方法:
pd.merge(left=h1,right=h2,left_index=True,right_index=True,how='inner')
也可以指定 左右表關聯的字段哦
data = pd.merge(left=intopiece_label, right=intopiece_pr, how="inner", left_on="order_number",right_on="order_number")
我們來詳解一下merge的參數,left
和rgiht
分別對應着需要連接的左表和右表,這裏語數外成績表是左表,籃球、舞蹈成績是右表。
left_index
與right_index
是當我們用索引(這兩個表的名字在索引中)連接時指定的參數,設置爲on表示用該表的索引作爲連接的條件(或者說橋樑)。假設姓名是單獨的一列值,且需要根據姓名進行匹配,那就需要用·left_on = ‘姓名’,right_on = '姓名·,我們可以分別指定左表的匹配列和右表的匹配列。
how
是指定連接方式,這裏用的inner
,表示我們基於姓名索引來匹配,只返回兩個表中共同
(同時出現)姓名的數據。下面詳解一下inner還涉及到的其他參數——left
、right
、outer
。
左右連接(left和right):
左連接(left)和右連接(right),我們可以直觀理解爲哪邊的表是老大,誰是老大,就聽誰的(所有行全部保持),先看左連接,左表h1原封不動,右邊根據左表進行合併,如果存在相關的名字,就正常返回數據,如果不存在(韓梅梅、李雷),就返回空(NAN)值;右連接就是聽右表的,左表有則返回無則爲空。
外連接(outer):
外連接是兩張表妥協的產物,我的數據全保留,你的也全保留,你有我無的就空着,你無我有的也空着。跟SQL中的操作幾乎類似。
2 刪——刪空去重
1. 刪空
在一些場景,源數據的缺失(空值)對於分析來說是干擾項,需要系統的刪除。上文我們合併後的df數據集就是有缺失數據的:
要刪除空值,一個dropna
即可搞定:
dropna
函數默認刪除所有出現空值的行,即只要一行中任意一個字段爲空,就會被刪除。我們可以設置subset
參數,例如dropna(subset = ['city'])
,來指定當一行中的city
字段爲空時,纔會被刪除。
2. 去重
drop_duplicates()
說是講去重,但是案例數據比較乾淨,沒有兩行數據是完全一樣的,所以我們要製造點困難,增加幾行重複值:
drop_duplicates
方法去重默認會刪掉完全重複
的行(每個值都一樣的行),如果我們要刪除指定列重複的數據,可以通過指定subset
參數來實現,假如我們有個奇葩想法,要基於流量級別
這列進行去重,則可以:
我們會發現,流量有三個級別,通過指定subset參數,我們刪除了這個字段重複的行,保留了各自不重複的第一行。繼續展開講,在源數據中,流量渠道爲一級
的有7行數據,每行數據其他字段都不相同,這裏我們刪除了後6行,只保留了第一行,但如果我們想在去重的過程中刪除前面6行,保留最後一行
數據怎麼操作?答案很簡單,指定keep
參數即可。
keep
值等於last
,保留最後一行數據,不輸入keep
值時,系統默認會給keep
賦值爲first
,就會保留第一行數據而刪掉其他的。
3 查——基於條件查詢
查,不是單純的返回幾行數據,而是根據業務實際需求,基於一定的條
件查看和選擇數據。
1 按條件索引/篩選
loc獨白
:你沒有看錯,哥的分量實在是太重了,所以又來搶個沙發,刷個臉熟。
需求
:是篩選出訪客數大於10000的一級渠道,loc一下:
2. 3.2 排序
很多情況下,我們都需要通過排序來觀察數據規律,以及快速篩選出TOP N的數據項。對於案例數據,我們怎麼樣按交易金額進行排序並篩選出TOP3的渠道呢?
問題的關鍵就在於排序,這個時候sort_values函數就派上用場了:
整個操作十分簡單,sort_values
函數,顧名思義是按照數值進行排序,首先要傳入的參數是列參數
,即我們根據哪一列的數值來進行排序,ascending
參數決定了排序順序,等於Flase則是從大到小的降序,設置爲True則是升序。
排序完之後,篩選TOP3渠道就非常簡單:
補充一個知識點,如果跟着文章操作,會發現無論是刪空的dropna,還是去重的drop_duplicates,或者是排序的sort_values,在對源數據進行操作後,源數據並未改變
,這是因爲我們沒有對這幾個函數的inplace
值進行設置,如果設置成inplace = True
,刪空、去重和排序都會在源數據上生效
。
但這裏爲了避免出現不必要的錯誤而無法更改,更建議大家把操作後的源數據賦值給新的變量
,如new = df.dropna()
,而不是將源數據的inplace參數設置爲True。跟Scala 還有Spark的 機制類似。
4 分——分組和切分
話天下大勢,合久必分,數據亦是如此。在分組的版塊中,我們重點介紹groupby
分組和cut
切分。
1分組
在案例數據中,總的流量級別有三級,每一級下又有多個投放地區,如果我們想彙總看每個級別流量所對應的總訪客數和支付金額,就需要用到分組了。
groupby是分組函數,最主要的參數是列參數
,即按照哪一列或者哪幾列(多列要用列表外括
)進行彙總,這裏是按照流量級別:
可以看到,直接分組之後,沒有返回任何我們期望的數據,要進一步得到數據,需要在分組的時候對相關字段進行計算(常用的計算方法包括sum、max、min、mean、std):
後面加上了sum,代表我們先按照流量級別進行分組,再對分組內的字段求和。由於沒有指定求和的列,所以是對所有數值型字段進行了求和。此處我們只想要各級別流量下的訪客數和支付金額,需要指明參數:
流量級別作爲彙總的依據列
,默認轉化爲索引列
,如果我們不希望它變成索引
,向groupby內傳入參數as_index = False
即可:
2 切分
切分(分桶)操作常用於一維數組的分類
和打標
,cut函數能夠高效的完成任務。它的主要參數和用法如下:
pd.cut(x,bins,right,labels)
- 第一個參數
x
是我們要傳入跟切分的一維數組,可以是列表,也可以是DataFrame的一列 bins
表示切分方式,可以自定義傳入列表[a,b,c] 表示按照a-b-c區間進行切分,也可以輸入數值(比如5)直接將數據分成5份。right
的值可以設置爲True 或 False,當爲True時候表示分組區間是包含右邊,不包含左邊。等於False表示含左不含右。labels
就是打標參數,我們把某列數據切分爲3組,每一組給他們設置一個標籤 比如[低,中,高]
不要被複雜的解釋迷惑,一個例子就完全搞懂了。以案例數據爲例,每個渠道都有對應的訪客數,我們現在希望對各渠道訪客級別進行評估,按照訪客數大小,分成辣雞(流量100以內的)、百級、千級和萬級的渠道。
因爲我們想對流量級別進行百、千、萬的歸類,所以把分組數值標準傳入bins參數
。從結果可以看到,在不設置right的情況下,分組區間是默認左開右閉的
,而我們希望的是左閉右開,即百級流量渠道訪客數在0-99之間,所以需要將right值設置爲False。
下面我們直接對分組後的數據進行打標,訪客數在0-99設置爲辣雞
,100-999設置爲百級,千級和萬級以此類推,同時將打好標籤的數據作爲新列給到源數據:
df['分類標籤'] = pd.cut(x=df['訪客數'],bins=[0,100,1000,10000,100000],right=False,labels=['垃圾','百級','千級','萬級'])
非常高效,一行半代碼就搞定了分組、判斷和打標的過程。
總結
本文從增
、刪
、查
、分
四個模塊,分別介紹了橫向
、縱向
合併;刪空
、去重
;篩選
、排序
和分組
、切分
等數據清洗過程中的常見操作。在實際運用中,各操作往往是你中有我,我中有你,共同爲了營造一個乾淨
的數據而努力。