纯python进行时区计数
import pandas as pd
import numpy as np
import json
path = 'example.txt'
open(path).readline()#只读取文件的第一行
open(path).readlines()#读取文件的所有行
records = [json.loads(line) for line in open(path)]
records[0]
#找到数据中最常出现的‘tz’时区
time_zones = [rec['tz'] for rec in records if 'tz' in rec]#这里要考虑并不是索引记录都有时区字段
time_zones[:10]
两种计数方法,认真理解!
def get_counts(sequence):
counts = {}
for x in sequence:
if x in counts:
counts[x]+=1
else:
counts[x]=1
return counts
counts = get_counts(time_zones)
counts
from collections import defaultdict
def get_counts2(sequence):
counts = defaultdict(int)#值将会初始化为0
for x in sequence:
counts[x]+=1
return counts
counts2 = get_counts2(time_zones)
counts2
def top_counts(counts2,n=10):
value_key_pairs = [(value,key) for key,value in counts2.items()]
value_key_pairs.sort()
return value_key_pairs[-n:]
top_counts(counts)
第二种方法,认真理解
from collections import Counter
counts = Counter(time_zones)
counts.most_common(10)
使用pandas进行时区计数
frame = pd.DataFrame(records)
frame.info()
frame.head()
frame['tz'].value_counts()[:10]
数据清理
用fillna方法替换缺失值,为空字符串使用布尔索引:
clean_tz = frame['tz'].fillna('missing')
clean_tz[clean_tz==''] = 'Unknown'
tz_counts = clean_tz.value_counts()
tz_counts[:10]#可以看出结果与上面不同
这里画的是时区计数的柱状图
import seaborn as sns
subset = tz_counts[:10]
sns.barplot(x=subset.values,y=subset.index)
a列包含了网址缩短的浏览器、设备或引用的信息:
frame['a'][1]
'GoogleMaps/RochesterNY'
frame['a'][50]
'Mozilla/5.0 (Windows NT 5.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2'
frame['a'][51][:50]#很长的一行,这里选前50个值
'Mozilla/5.0 (Linux; U; Android 2.2.2; en-us; LG-P9'
#分离字符串中的第一个标记
results = pd.Series([x.split()[0] for x in frame['a'].dropna()])
results[:5]
0 Mozilla/5.0
1 GoogleMaps/RochesterNY
2 Mozilla/4.0
3 Mozilla/5.0
4 Mozilla/5.0
dtype: object
results.value_counts()[:8]
Mozilla/5.0 2594
Mozilla/4.0 601
GoogleMaps/RochesterNY 121
Opera/9.80 34
TEST_INTERNET_AGENT 24
GoogleProducer 21
Mozilla/6.0 5
BlackBerry8520/5.0.0.681 4
dtype: int64
将时区计数多的时区记录分解为Windows和非Windows用户。
想计算一个代表每一行是否是Windows的值:
cframe = frame[frame.a.notnull()]
cframe.loc[:,'os']=np.where(cframe.loc[:,'a'].str.contains('Windows'),'Windows','Not Windows')
#where的用法,满足条件(condition),输出x,不满足输出y。
cframe.head()
agg_counts = cframe.groupby(['tz','os']).size().unstack().fillna(0)
#分组后在将内层索引拆分为行标签
agg_counts.head()
选出总体计数最高的时区
#选出总体计数最高的时区
indexer = agg_counts.sum(1).argsort()#返回数组从小到大的索引值
indexer[:10]
tz
24
Africa/Cairo 20
Africa/Casablanca 21
Africa/Ceuta 92
Africa/Johannesburg 87
Africa/Lusaka 53
America/Anchorage 54
America/Argentina/Buenos_Aires 57
America/Argentina/Cordoba 26
America/Argentina/Mendoza 55
dtype: int64
#使用take按顺序选出行,之后再对最后10行(也就是最大的10个值)进行切片
count_subset = agg_counts.take(indexer[-10:])
count_subset[:]
有一个便捷的的方法叫做nlargest,可以做同样的事情:
agg_counts.sum(1).nlargest(10)
agg_counts.sum(1).sort_values()[-10:]
count_subset = count_subset.stack()#堆叠进来
count_subset.name = 'total'
count_subset = count_subset.reset_index()#重置索引,把分组索引拿进来别称列标签
count_subset[:10]
sns.barplot(x='total',y ='tz',hue='os',data=count_subset)
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)
#用transform更为高效的计算归一化之和
g = count_subset.groupby('tz')
result2 = count_subset.total/g.total.transform('sum')
sns.barplot(x=result2,y='tz',hue='os',data=results)
很简单的一个案例,几个细节:unstack(),where(),for循环后面的if条件判断,defaultdict()的应用,json文件的读取,nlargest(),argsort(),take()等方法要熟悉。
网友评论