fbpx

Open Data:

Mobile App Statistics (Apple iOS app store)

上一篇文章中,我們介紹了如何檢視與定位資料,並且在文章最後提到「我們在提取 index 的時候,較常使用 mask 進行條件篩選」,這個條件篩選的方法是 pandas 套件中非常重要的功能,也是這篇文章的核心重點。

  • 使用資料表

Notebook Content:

這次我們會使用apple(AppleStore.csv)的公開資料,其中紀錄了兩個app平台商店中所有app的分類、評分、下載量、名稱、大小⋯⋯等相關資料,假設我們是一間app開發公司的分析人員,我們想研究目前市場中哪些分類的評分以及下載量是比較高的。

資料條選件篩選:


首先我們先試著從資料中提取 price 欄位的前20筆資料,看一下app的價格有哪些:

print(app['price'].head(20))
0     0.00
1     0.00
2     0.00
3     0.00
4     0.00
5     0.00
6     0.00
7     0.00
8     0.00
9     0.00
10    0.00
11    1.99
12    0.00
13    0.00
14    0.00
15    0.00
16    0.00
17    0.99
18    6.99
19    0.00
Name: price, dtype: float64

從前20筆app的價格中可以看到,大部分app是免費的,而有些則需要1.99美金與6.99美金,當然這只是前20筆資料,在所有app中可能有非常多種的價格,但假設我們的app公司要開發的軟體是免費的,所以我們在分析的時候只需要使用到價格為0.0的app資料

 

在Python中有所謂的「比較運算子」也就是 == , != , > , < , >= , <= 這些,在進行兩數值比較時會依據「比較結果是否符合運算條件」回傳 TrueFalse 兩種布林值。其實在 pandas 套件也存在比較運算子的機制,只需要使用 Series比較運算子比較值 的格式,pandas會將Series 中的每一個值與比較值進行比較運算,並回傳布林值作為新的 Series ,所以我們現在就利用比較運算的方式比較price 欄位的每個軟體價格是否為免費吧!

print(app['price']==0)
0        True
1        True
2        True
3        True
4        True
5        True
6        True
7        True
8        True
9        True
10       True
11      False
12       True
13       True
14       True
15       True
16       True
17      False
18      False
19       True

因為篇幅問題所以我們只顯示前20筆結果,你可以跟上面的 Series 比較一下,如果上面的資料為 0.0 那這邊的同一個 index 結果應為 True ,反之則為 False

 

接著我們要繼續利用這個布林值的 Series ,首先我們先將這個 Series 賦値為變數 mask ,並將他放進 df.loc[,] 中,然後將 mask 放在 index 的位置,然後我們提取 price 欄位,並顯示前20筆結果:

mask = app['price'] == 0
print(app.loc[mask,'price'].head(20))
0     0.0
1     0.0
2     0.0
3     0.0
4     0.0
5     0.0
6     0.0
7     0.0
8     0.0
9     0.0
10    0.0
12    0.0
13    0.0
14    0.0
15    0.0
16    0.0
19    0.0
20    0.0
21    0.0
22    0.0
Name: price, dtype: float64

從結果可以看到,同樣是欄位 price ,但全部20筆的資料都變成了 0.0 ,而且左邊的 index 也有些不同:少了11,17,18號資料,這就是最基本的條件篩選方法,利用比較運算回傳的布林值 Series 作為mask(遮罩),選取符合條件(True)的所有資料,下圖是我們篩選資料的示意圖,你可以把這次的操作理解為「選取符合條件(mask)的 price 欄位資料」。

然而在進行資料篩選時,是可以有多個條件的,也就是Python的 andor ,不過在 pandas 套件中是我們是使用 &| 的符號表示。假設我們現在想篩選「免費」而且是「遊戲分類」的軟體,所以我們就必須設定條件:「 price 欄位為 0.0 prime_genre 欄位為 “Games” 」的所有資料,我們先分別看一下這兩個條件的結果:

條件一:價格為免費

print(app['price']==0)

條件二:分類為遊戲

app['prime_genre']=='Games'

 

結果一:

11      False
12       True
13       True
14       True
15       True
16       True
17      False
18      False
19       True
20       True
......

結果二:

11       True
12       True
13       True
14       True
15       True
16       True
17       True
18       True
19       True
20      False
......

因為篇幅問題我們只顯示其中幾筆資料結果,從上面的兩個布林值結果可以看到,結果一有7筆資料符合條件(True),結果二則有9筆資料符合,這時候我們使用 & 把兩個條件串起來試試:

ps.記得在使用 & | 的時候,兩邊的條件需要使用小括號包起來,否則會出現 error !

print((app['price']==0) & (app['prime_genre']=='Games'))
11      False
12       True
13       True
14       True
15       True
16       True
17      False
18      False
19       True
20      False
......

上面為兩個條件的篩選結果,因為是使用 & (且)所以當兩邊結果都是 True 時,合併的結果才會顯示 True ,像是第20號資料雖然價格是免費,但是他並非遊戲分類,所以最後的合併結果為 False ,如果我們改成使用 | (或)的話,結果如下:

print((app['price']==0) | (app['prime_genre']=='Games'))
11       True
12       True
13       True
14       True
15       True
16       True
17       True
18       True
19       True
20       True
......

因為兩邊的條件都至少有一邊符合,所以這邊的10筆資料結果全部都是 True

現在我們試著將這個篩選結果的布林值 Series 作為遮罩(mask),放進df.loc[,] 進行資料定位,這邊我們只提取「名稱」、「價格」、「分類」三個欄位:

mask = (app['price']==0) & (app['prime_genre']=='Games')  #篩選條件
cols = ['track_name','price','prime_genre']  #提取名稱、價格、分類欄位
print(app.loc[mask,cols].head(10))
                             track_name  price   prime_genre
2                        Clash of Clans    0.0         Games
3                            Temple Run    0.0         Games
7                      Candy Crush Saga    0.0         Games
9                           Angry Birds    0.0         Games
10                       Subway Surfers    0.0         Games
12                            Solitaire    0.0         Games
13                           CSR Racing    0.0         Games
14  Crossy Road - Endless Arcade Hopper    0.0         Games
15             Injustice: Gods Among Us    0.0         Games
16                              Hay Day    0.0         Games

從結果可以看到我們成功篩選了「免費的遊戲軟體」,在這次使用的程式碼中有個需要注意的地方,就是易讀性的問題,雖然我們可以把所有的條件與提取欄位都寫在 df.loc[,] 中,但是這樣會得到一串非常長的程式碼,其實會大大降低我們程式碼的易讀性。我們在進行資料分析的時候常常是一個團隊一起執行,這時候程式碼的易讀性就顯得非常重要,所以我們應該要養成好習慣,過長的程式碼可以另外賦值為變數,並適時寫一些註解,幫助團隊可以更快理解這段程式碼。

 

df.groupby() 資料分組


除了直接使用條件篩選資料以外,我們也可以使用「分組」的方式篩選資料,這種方法是利用單一欄位將資料進行分組,比如說 prime_genre 欄位中有所有的軟體分類,這時候我們想看看不同分類的軟體平均價格,這時候就很適合使用 df.groupby() 方法,此方法的使用方式非常的簡單,只要在方法中引入你想要作為分組依據的欄位名稱即可,像是現在我們想分組所有的分類:

groups = app.groupby('prime_genre')
print(groups)

這時我們發現一件事,分組之後,pandas回傳了一個新的物件 groupby

<pandas.core.groupby.generic.DataFrameGroupBy object at 0x11af94780>

基本上我們無法直接使用 groupby 物件,需要額外的方法才可以使用,那就是利用方法groupby.get_group() 直接取出整組資料。

 

groupby.groups 各組的資料index值


我們現在已經將資料依照 prime_genre 欄位中的不同類別進行分組,但我們剛才直接將結果印出來,卻得到了一個新的 groupby 物件,這邊要解釋一下,groupby 物件記錄了每一個分類組別中的所有資料的 index 值,這點我們可以利用他的一個 groups 屬性驗證:

groups = app.groupby('prime_genre')
print(groups.groups)

利用這個屬性我們可以看到,這個屬性是一個 dict() 裡面每一個key值都是一個分類,每一個分類都有一個相對應的陣列,陣列中的數字就是這個分類資料的 index 值,例如:「書」的分類軟體有第77,208,244,285…..號資料,而「商用」的軟體有第419, 489, 513, 529, 584, 682…號資料,以此類推:

{'Book': Int64Index([ 77, 208, 244, 285, 364, 1270, 1996, 2186, 2203, 2481,
            ..., 7080, 133, 7137, 7145, 7153, 7159, 7167, 7171, 7188, 7193],
            dtype='int64', length=112),
'Business': Int64Index([ 419,  489,  513,  529,  584,  682,  934, 1092, 1098, 1119, 1149,
            1222, 1286, 1343, 1679, 1680, 1709, 1757, 1764, 1977, 2055, 2143,
            2335, 2394, 2479, 2487, 2564, 2666, 2685, 2701, 2702, 2710, 2767,
            3208, 3370, 3392, 3541, 3909, 3939, 4054, 4098, 4171, 4495, 5020,
            5168, 5172, 5192, 5209, 5805, 5808, 5922, 5974, 5988, 6428, 6441,
            6650, 7025],
            dtype='int64'),
'Catalogs': Int64Index([ 862, 2028, 2387, 3276, 3891, 6374, 6418, 6464, 6674, 6881],
            dtype='int64'),
'Education': Int64Index([ 122, 169, 227, 311, 373, 446, 610, 672, 674, 685,
            ..., 7081, 7087, 7097, 7107, 7110, 7129, 7148, 7150, 7157, 7190],
            dtype='int64', length=453),
'Entertainment': Int64Index([ 55, 61, 78, 99, 104, 114, 177, 193, 215, 221,
            ......]}

 

groupby.get_group(group_value) 提取組資料方法


不過光是知道有哪些編號似乎無法做什麼,必須要能顯示整組資料才行,所以我們要使用方法 group.get_group() ,這個方法只要在括弧中引入我們要顯示的分類即可,像下面的程式碼:

print(group.get_group('Book').head())  #因為df.head()本身預設為顯示前五筆資料,所以我們就不特別設定

結果他回傳了第77,208,244,285,364號資料,這剛好就是上面 dict 中key值為 ‘Book’ 的陣列中的前五個號碼且仔細看他們的 prime_genre 欄位值都是 Book

             id                                         track_name  
77    302584613        Kindle – Read eBooks, Magazines & Textbooks   
208   379693831  Audible – audio books, original series & podcasts   
244  1031002863       Color Therapy Adult Coloring Book for Adults   
285   366869252          OverDrive – Library eBooks and Audiobooks   
364  1024818709                              HOOKED - Chat Stories   

     size_bytes currency  price  rating_count_tot  rating_count_ver  
77    169747456      USD    0.0            252076                80   
208    81558528      USD    0.0            105274              1774   
244   135236608      USD    0.0             84062              1450   
285    39844864      USD    0.0             65450              2721   
364    94545920      USD    0.0             47829               708   

     user_rating  user_rating_ver     ver cont_rating prime_genre  
77           3.5              4.5    5.11          4+        Book   
208          4.5              4.5    2.23          4+        Book   
244          5.0              4.5     2.0          4+        Book   
285          4.0              4.5   3.6.4          4+        Book   
364          4.5              4.5  2.28.0          9+        Book   

     sup_devices.num  ipadSc_urls.num  lang.num  vpp_lic  
77                37                5         9        1  
208               37                5         5        1  
244               37                4         2        1  
285               37                5        18        1  
364               37                0         8        1

從結果的格式你應該能夠看得除來,groups.get_group() 方法會回傳 DataFrame 物件,所以我們能在取得分組資料後繼續使用 df 的方法進行資料處理,比如說欄位提取、查看空值、資料清理……等,這就是這個方法方便的地方。

我們到現在已經學會了讀取資料、檢視資料、定位部份資料與如何將資料進行分組等方法,下一篇我們要開始進入資料清理的範圍,這是資料科學中非常重要的一環,好的資料清理可以增加後續的分析與視覺化的效率,也能夠讓我們在清理的過程中更熟悉這份資料的細節。

 

Written by

Glove Yen

一個不務正業的企管人,喜歡有創造性的事物,從管理到設計到程式,目前正在鑽研資料科學以及網頁前端開發,不知從什麼時候開始已經習慣了每天coding的日子。

—轉自好文作者Glove Yen_Data Science_Python資料處理套件part3-Pandas條件篩選資料
如果你喜歡他的文章、Python資料分析有興趣,歡迎回到他的Blog: glove-coding看更多:)

或接續觀看Pandas 第5講:Python資料處理套件Pandas整理資料欄位與型別

 

📒 Python Pandas 系列文章:

Pandas 第1講:Python資料處理套件Pandas簡介

Pandas 第2講:Python資料處理套件Pandas資料儲存物件

Pandas 第3講:Python資料處理套件Pandas檢視與定位資料

Pandas 第4講:Python資料處理套件Pandas條件篩選資料(本文)

Pandas 第5講:Python資料處理套件Pandas整理資料欄位與型別

Pandas 第6講:Python資料處理套件Pandas 資料字串處理

Pandas 第7講:Python資料處理套件Pandas數值處理與基礎統計量

快樂學程式在Udemy 也推出了以Pandas 套件進行資料處理的實戰課程,這次是將Python已視覺化的方式

對資料進行解析,只要一個假日拉高你的職場競爭力!快來這裡一起快樂學程式!

如果你的入門還在單打獨鬥,歡迎來到快樂學程式找到志同道合的夥伴,你的自學之路不孤單。

Leave a Reply