数据分析案例(USA.gov)

来自Bitly的USA.gov数据

2011年,URL缩短服务Bitly跟美国政府网站USA.gov合作,提供了一份从生成.gov或.mil短链接的用户那里收集来的匿名数据。

以每小时快照为例,文件中各行的格式为JSON:

读取文件

使用json模块及其loads函数逐行加载已经下载好的数据文件

import json 

records = [json.loads(line) for line in open(path)]
部分加载数据

用纯Python代码对时区进行计数

求该数据集中常出现的是哪个时区(即tz字段)

time_zones = [rec['tz'] for rec in records] 
错误命令

因为并不是所有记录都有时区字段

time_zones = [rec['tz'] for rec in records if 'tz' in rec]
取数据集中出现的前10个时区

对时区进行计数,这里介绍两个办法:一个较难(只使用标准Python库),另一个较简单(使用pandas)

计数的办法之一是在遍历时区的过程中将计数值保存在字典中

def get_counts(sequence):    
    counts = {}
    for x in sequence:
        if x in counts:
            counts[x] += 1
        else:
            counts[x] = 1
    return counts

from collections import defaultdict
def get_counts2(sequence):
    counts = defaultdict(int)  # values will initialize to 0 
    for x in sequence:
        counts[x] += 1
    return counts

defaultdictt的作用是在于,当字典里的key不存在但被查找时,返回的不是keyError而是一个默认值(返回的是工厂函数的默认值,比如list对应[ ],str对应的是空字符串,set对应set( ),int对应0)

统计纽约出现的次数

要得到前10位的时区及其计数值

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:]
前10位的时区及其计数值

collections.Counter类,它可以使这项工作更简单

from collections import Counter

counts = Counter(time_zones)

counts.most_common(10) 
前10位的时区及其计数值

用pandas对时区进行计数

import pandas as pd

frame = pd.DataFrame(records)
frame.info()
生成Pandas数据
部分数据查看

对Series使用value_counts方法

tz_counts = frame['tz'].value_counts()
计数后取前十

可以用matplotlib可视化这个数据。为此,我们先给记录中未知或缺失的时区填上一个替代值。fillna函数可以替换缺失值(NA),而未知值(空字符串)则可以通过布尔型数组索引加以替换

clean_tz = frame['tz'].fillna('Missing')

clean_tz[clean_tz == ''] = 'Unknown'

tz_counts = clean_tz.value_counts()
画图之前进行数据清理

用seaborn包创建水平柱状图

import seaborn as sns

subset = tz_counts[:10]
sns.barplot(y=subset.index, x=subset.values)
创建水平柱状图

a字段含有执行URL短缩操作的浏览器、设备、应用程序的相关信息

抽样检查

将这些”agent”字符串中的所有信息都解析出来是一件挺郁闷的工作。一种策略是将这种字符串的第一节(与浏览器大致对应)分离出来并得到另外一份用户行为摘要

results = pd.Series([x.split()[0] for x in frame.a.dropna()])
与浏览器大致对应的数量统计

假设想按Windows和非Windows用户对时区统计信息进行分解。为了简单起见,我们假定只要agent字符串中含有”Windows”就认为该用户为Windows用户。由于有的agent缺失,所以首先将它们从数据中移除

cframe = frame[frame.a.notnull()]

然后计算出各行是否含有Windows的值

cframe['os'] = np.where(cframe['a'].str.contains('Windows'),  'Windows', 'Not Windows')
计算前5行是否含有Windows的值

根据时区和新得到的操作系统列表对数据进行分组

by_tz_os = cframe.groupby(['tz', 'os'])

分组计数,类似于value_counts函数,可以用size来计算。并利用unstack对计数结果进行重塑

agg_counts = by_tz_os.size().unstack().fillna(0)
不同时区内使用操作系统的对比

根据agg_counts中的行数构造了一个间接索引数组

indexer = agg_counts.sum(1).argsort()
构造间接索引数组

通过take按照这个顺序截取了后10行大值

count_subset = agg_counts.take(indexer[-10:])
take

pandas有一个简便方法nlargest,可以做同样的工作

nlargest

传递一个额外参数到seaborn的barpolt函数,来画一个堆积条形图

count_subset = count_subset.stack()

count_subset.name = 'total'

count_subset = count_subset.reset_index()

count_subset[:10] 
堆积条形图

这张图不容易看出Windows用户在小分组中的相对比例,因此标准化分组百分比之和为1

def norm_total(group):
    group['normed_total'] = group.total / group.total.sum()
    return group

results = count_subset.groupby('tz').apply(norm_total)

sns.barplot(x='normed_total', y='tz', hue='os',  data=results)
标准化分组百分比

还可以用groupby的transform方法,更高效的计算标准化的和

g = count_subset.groupby('tz')

results2 = count_subset.total / g.total.transform('sum')

你可能感兴趣的:(数据分析案例(USA.gov))