概述
該系列是關于《利用Python進行數據分析》的學習筆記,對應 引言 > 來自bit.ly的1.usa.gov數據 部分。
來自bit.ly的1.usa.gov數據
注意:該部分使用了《利用Python進行數據分析》的數據,可以去pydata-book - github下載數據。另外,使用Spyder進行該次實驗,記得將文件目錄設置為對應的pydata-book
。
下列代碼用來載入數據,了解數據格式:
# 數據集對應路徑
path = 'ch02/usagov_bitly_data2012-03-16-1331923249.txt'
# 顯示數據集的第一行
open(path).readline()
# 此處應該可以看到一長串字符串,為JSON格式
下列代碼使用Python中內置的JSON庫,將上述JSON格式的字符串轉化為Python的字典對象:
import json
path = 'ch02/usagov_bitly_data2012-03-16-1331923249.txt'
records = [json.loads(line) for line in open(path)] # 轉化為Python的字典對象
records[0] # 檢查第一條記錄
對時區進行計數(純Python代碼)
該部分用來對上述數據集中的時區字段(tz
字段)進行計數。
# 導入數據,并轉化為Python字典對象
# 下列代碼會報錯,因為并不是所有記錄都有'tz'這個字段
# time_zones = [rec['tz'] for rec in records]
time_zones = [rec['tz'] for rec in records if 'tz' in rec]
# 檢查數據集中時區字段的前十個
time_zones[:10]
之后再使用純Python代碼對time_zones
進行計數,思路是遍歷字典慢慢數:
def get_counts(sequence):
counts = {}
for x in sequence:
if x in counts:
counts[x] += 1
else:
counts[x] = 1
return counts
或者,使用Python的標準庫defaultdict
:
from collections import defaultdict
def get_counts(sequence):
counts = defaultdict(int) # 所有的值均會被初始化為0
for x in sequence:
counts[x] += 1
return counts
注意,defaultdict
的特性可以參見The Python Standard Library。簡單來說,就是會用特定類型的默認值初始化第一次出現的鍵。
之后,進行測試:
counts = get_counts(time_zones)
counts['America/New_York'] # 檢查New York這個時區的計數情況
如果想得到時區計數的前十名及對應的時區,可以使用如下代碼:
def top_counts(count_dict, n=10):
value_key_pairs = [(count, tz) for tz, count in count_dict.items()]
value_key_pairs.sort()
return value_key_pairs[-n:]
top_counts(counts)
當然,你也可以使用Python標準庫collections.Counter來完成上述任務:
from collections import Counter
counts = Counter(time_zones) # 計數
counts.most_common(10) # 計數前十
注意,可以參見The Python Standard Library了解更多關于Counter
的細節。
使用pandas對時區進行計數
實現對時區的計數,只需要如下代碼:
from pandas import DataFrame, Series
import pandas as ps
import numpy as np
frame = DataFrame(records)
print frame # 檢視frame,一長串。這被稱為frame的摘要視圖(summary view)
# frame['tz']返回的為Series對象
# Series對象的value_counts方法會對其進行計數
tz_counts = frame['tz'].value_counts()
下面我們用這段數據生成一張圖片:
clean_tz = frame['tz'].fillna('Missing') # 用`Missing`替換缺失值
clean_tz[clean_tz == ''] = 'Unknown' # 用`Unknown`替換空白值
tz_counts = clean_tz.value_counts()
print tz_counts[:10] # 檢視計數的前十項
tz_counts[:10].plot(kind='barh', rot=0) # 繪圖,可視化的方式展示前十項
注意,Spyder中更改下設置,可以避免每次都要手動引入NumPy及Matploylib。具體來說,將Spyder > Tools > Preferences > IPython console > Graphics中Support for graphics
的Automatically load Pylab and NumPy modules
勾選上。
為熟悉pandas,我們再來看看字段a
,該字段含有執行URL短縮操作的瀏覽器、設備、應用程序的相關信息:
frame['a'][1]
# u'GoogleMaps/RochesterNY'
frame['a'][59]
# u'Mozilla/5.0 (iPhone; CPU iPhone OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Mobile/9B176'
我們現在來統計按Windows和非Windows用戶對時區統計信息進行分解,為簡單起見,我們假定字段a
中含有"Windows"就認為該用戶為Windows用戶,反之就認為為非Windows用戶。
cframe = frame[frame.a.notnull()] # 剔除字段`a`為空的數據
# 根據字段`a`分為Windows用戶和非Windows用戶
operating_system = np.where(cframe['a'].str.contains('Windows'),
'Windows', 'Not Windows')
# 根據時區和操作系統信息進行分組
by_tz_os = cframe.groupby(['tz', operating_system])
# size對分組結果進行計數
# unstack對計數結果進行重塑
agg_counts = by_sz_os.size().unstack().fillna(0)
最后,我們來選取最常出現的時區:
# 用于按升序排列
indexer = agg_counts.sum(1).argsort()
count_subset = agg_counts.take(indexer)[-10:]
# 生成一張堆積條形圖
count_subset.plot(kind='barh', stacked=True)
# 生成對應的比例圖
normed_subset = count_subset.div(count_subset.sum(1), axis=0)
normed_subset.plot(kind='barh', stacked=True)