使用Python Pandas分析處理Airbnb數據

Pandas是能夠讓Python成為數據分析編程語言的原因之一,它使得導入、分析和可視化數據變得更加容易。它能夠快捷地讀取CSVExcelJsonHtmlSQL等文件,其主要的2種數據結構是SeriesDataFrame。Series本質上是一個列,而DataFrame是一個由Series集合組成的多維表。


本文用Airbnb (愛彼迎) 的數據來學習Pandas基礎知識并初步探索首都北京的民宿特點。這些數據來源于網絡,官網上中國只有2個城市的數據,分別是Beijing和Hong Kong。這里采用關于北京的calendar.csv這個文件,可以通過鏈接進行下載。

另外本文是使用Python 3.7.4編寫的,使用Jupyter Notebook構建的。在演示之前需要導入pandasmatplotlib庫:

import pandas as pd 
import matplotlib.pyplot as plt

查看pandas版本,使用下面命令,是雙下劃線:

pd.__version__ 

我是將calendar.csv文件與工程文件放在同一目錄下的,直接根據文件名導入CSV文件:

calendar = pd.read_csv('calendar.csv')  

若不在同一目錄下,可以使用其完整路徑,路徑前的r是為了防止一些轉義字符:

calendar = pd.read_csv(r'C:\Users\ringo\Desktop\calendar.csv')

查看前5行數據,作用等價于使用calendar.head(),查看后5行可以使用tail()函數:

calendar[:5]  
隨機抽取5行數據
calendar.sample(5) 
查看行數和列數
calendar.shape   

輸出形式為元組(rows, columns),在這個數據表中共有 12681641行、7列,數據量之龐大。

查看索引、數據類型和內存信息

info()提供關于數據集的基本細節,比如行和列的數量、非空值的數量、每個列中的數據類型以及DataFrame使用了多少內存。

calendar.info()
顯示所有列的數據類型
calendar.dtypes  
isnull的使用

.isnull()本身不是很有用,通常與sum()等其他方法結合使用。

calendar.isnull().sum()

我們可以發現共有194 行Priceadjusted_price列值為null,6 行minimum_nightsmaximum_nights為null。

移除空值

數據分析經常會面臨輸入值為空的難題,這是一個需要對數據及其上下文有深入了解的決策。一般來說只建議在有少量遺漏的情況下刪除空數據。

calendar.dropna()

這個操作將刪除至少有一個空值的任何行,但是它將返回一個新的DataFrame,而不改變原來的數據。但我們也可以在這個方法中指定inplace=True,在原有的數據表上直接進行修改。

calendar.dropna(inplace=True)

除了刪除行之外,我們還可以通過設置axis=1來刪除空值的列。

axis=1是什么參數?

axis從何而來,為什么需要為1才能影響列,這些都不是很明顯。查看原因,只需查看.shape輸出 (12681441, 7),如上文所述這是一個元組,即12681441行和7列。注意在這個元組的索引0處,而在這個元組的索引1處。這就是為什么axis=1會影響列的原因。

unique 和 nunique的區別?

unique()以數組形式返回列的所有唯一值,而nunique()是返回的是唯一值的個數。

calendar.date.unique()
calendar.date.nunique()
print('有',calendar.date.nunique() , '天' , calendar.listing_id.nunique() ,'不同的清單在calendar中')

有 383 天 34744 不同的清單在calendar中

如何獲取列?

我們可以使用方括號['列名']的形式獲取列,當然也可以使用前者點語法。

calendar['date'] = calendar.date 
type(calendar.date)

pandas.core.series.Series

這將返回一個 Series,若要將列提取為DataFrame,需要傳遞列名列表:

date  = calendar[['date']]
type(date)

pandas.core.frame.DataFrame

如何獲取行?

一般情況下,有2種方式,根據名稱 loc 和根據index數值 iloc。方便演示,我們先來創建一個DataFrame:

demo = pd.DataFrame({'name'   :['Ringo','Jerry','Aliza','Grace','Tonny'],
                     'apples' :[1,3,0,3,6],
                     'oranges':[2,4,6,2,4]})
demo.set_index('name',inplace=True)  #重新設置name列為index

這樣我們就得到如下樣式的數據表:
demo.loc['Ringo']

另一方面,對于iloc,我們給它Ringo的數值索引0:

demo.iloc[0]

我們還可以按照這樣的方式進行多行選擇:

demo.loc['Ringo':'Aliza']
demo.iloc[0:3]

注意iloc[0:3]并不能抽取到Grace這行數據,這是因為使用.iloc進行切片與使用列表進行切片遵循相同的規則,不包括位于末尾索引處的對象。

當然我們也可以選擇任意列,比如選擇前3行,Oranges列:

demo.loc['Ringo':'Aliza',['oranges']]
min()和max()
calendar.date.min()
calendar.date.max()

我們有2019-09-23到2020-10-09超過一年的數據。列為available里的ft分別代表FalseTrue,即房間不可預訂和可預訂 。
我們來看下不可預訂和可預訂的比例?使用如下代碼可以輸出f,t對應的個數。

calendar.available.value_counts()
plt.axes(aspect='equal') # 將橫、縱坐標軸標準化處理,保證餅圖是一個正圓,否則為橢圓,等同于 plt.axis('equal')

plt.pie(calendar['available'].value_counts(),labels= ['Available','Not Available'],autopct='%.1f%%',radius = 1.2,colors= ['r','g'])

plt.title('Room available ratio') # 設置title

plt.show()

從餅圖中可以看出大概還有6成的房間可以預訂。


如果將上面的代碼修改成如下code,那么餅圖將有所改變,explode每一塊餅圖離開中心距離,默認值為(0,0)就是不離開中心;shadow 是否陰影,默認值為False,即沒有陰影;textprops 設置標簽(labels)和比例文字的格式,屬于字典類型,可選參數,默認值為None

plt.pie(
         calendar.available.value_counts(),
         explode=(0,0.1),  #Not Available區塊分離
         labels= ['Available','Not Available'],  #標簽
         autopct='%1.1f%%',  #顯示占比
         radius = 1.2,  #設置半徑
         colors = ['#abcdef','#ccddaf'], #設置顏色
         textprops={'fontsize':14,'color':'black'},  #設置字體、顏色
         shadow = True #顯示陰影 
)
plt.show()

另外可以設置成中文顯示標簽,代碼如下,自己去試試吧。

plt.rcParams['font.sans-serif']=['SimHei'] 

接下來我們研究下不同時間段的訂房率,將dateavailable兩列數據取出生成一個新的DataFrame, 將其命名為new_calendar

new_calendar = calendar[['date','available']]
什么是apply函數?

apply()函數形式如下:

DataFrame.apply(func, axis=0, broadcast=False, raw=False, reduce=None, args=(), **kwds)

func函數需要自己實現,函數的傳入參數根據axis來定,比如axis = 1,就會把一行數據作為Series的數據結構傳入給自己實現的函數中,我們在函數中實現對Series不同屬性之間的計算,返回一個結果,則apply函數會自動遍歷每一行DataFrame的數據,最后將所有結果組合成一個Series數據結構并返回。

新增一列available_num,當不可預訂時將其值設為1,反之為0。

new_calendar['available_num'] = calendar['available'].apply(lambda x:1 if x =='t' else 0)

當然此處我們也可以直接使用map()函數,效果是一樣的:

new_calendar['available_num'] = calendar['available'].map({'f':0,'t':1})
SettingWithCopyWarning

運行后發現彈出一條SettingWithCopyWarning警告:


可以參考網上SettingwithCopyWarning 的原理和解決方案,我們可以進行copy()操作或者采用loc方法。

new_calendar = calendar[['date','available']].copy()

new_calendar = calendar.loc[:,['date','available']]
new_calendar[:5]
什么是groupby?

groupby()操作一般涉及拆分對象(Splitting)、應用函數(Applying)以及組合結果(Combining)的組合。它可以用于對大量數據進行分組,并在這些組上進行計算操作。如組內計數、求和、求均值以及求方差等。
Splitting —— 通過對數據集應用一些條件將數據分組;
Combining —— 將一個函數獨立地應用于每個組;
Combining —— 將groupby和結果應用到數據結構中,然后合并不同的數據集。

根據不同日期進行分組,求計算已經預定的平均值:

new_calendar = new_calendar.groupby('date')[['available_num']].mean()
new_calendar.rest_index(inplace = True)
new_calendar[:5]

使用雙括號索引[['available_num']]是為了直接自動返回一個DataFrame對象,這樣index會直接變成date,使用reset_index()后又可以重新生產index,date變成列。

什么是dt和str?

Series對象和DataFrame的列數據提供了catdtstr三種屬性接口,分別對應分類數據、日期時間數據和字符串數據。
DataFrame數據中的日期時間列支持dt接口,該接口提供了dayofweekdayofyearis_leap_yearquarterweekday_name等屬性和方法,DataFrame數據中的字符串列支持str接口,該接口提供了centercontainscountendswithfindextractlowersplit等大量屬性和方法,大部分用法與字符串的同名方法相同,少部分與正則表達式的用法類似。

時間處理to_datetime()函數
new_calendar['date'] = pd.to_datetime(new_calendar.date,format = '%Y%m%d') 
圖表顯示
plt.figure(figsize = (10 , 8))
plt.plot(new_calendar['date'] , new_calendar['available_num']*100)
plt.title('Airbnb Beijing Calendar')
plt.ylabel('Room available rate (%)')
plt.show()

圖中可見今年國慶節前后房間可預訂率明顯下降,說明很多人在國慶出游訂房。到了2020年元旦時可預訂率又直線下降。但明年4月過后為何又那么多人訂房?是春游、暑假嗎?


接下來再來看看北京哪個月的民宿較為便宜?

calendar[:5]     #查看前5行
calendar[-5:]  #查看后5行


發現price列里的數據有,$符號,我們需要將其統一替換掉,另外使用info()函數發現price列是object,需要將其強轉成float類型.

calendar['price'] = calendar['price'].str.replace(',','').str.replace('$','').astype(float)
什么是strftime?

strftime函數是將字符串按照后面的格式轉換成時間元組類型。

mean_price_of_month = calendar.groupby(calendar['date'].dt.strftime('%b') , sort = False)['price'].mean()
mean_price_of_month.plot('bar',figsize=(12,7))
plt.ylabel('Average monthly price')
plt.xlabel('Month')
plt.show()

下圖可以觀察到每個月的北京的民宿平均價格差異不大,沒有明顯的淡旺季之分。

最后再來看看每天的平均價格如何?

calendar['dayofweek'] =calendar.date.dt.weekday_name
weekday = calendar['dayofweek'].unique().tolist()

['Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday', 'Monday']
沒有按照周一到周日的順序,手動調整數組元素順序:

weekday = ['Monday','Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ]

使用groupby按照周幾進行分組,再對價格求平均值并進行圖表顯示。

price_of_weekday = calendar.groupby('dayofweek')['price'].mean().reindex(weekday)
plt.figure(figsize=(10,8))
plt.plot(price_of_weekday,linewidth=3, color='orange',marker= 'o',markerfacecolor='r', markersize= 8)
plt.xlabel('Day of week')  #x軸坐標
plt.ylabel('Price(Yuan)')   #y軸坐標
plt.title('Average Price of Weekday')  #設置標題
plt.grid()  #顯示網格

跟預期結果一樣,周五和周六民宿價格要稍貴一些。但是平均價格都在700+元以上,這個感覺有點不符合實際情況。

最后將code放在GitHub_ Pandas_tutorial上,歡迎評論、指正。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容