Pandas (一): 基本操作

数据来源

本系列参考的书目是

用到的数据来自 https://github.com/pydata/pydata-book

处理 usa.gov 数据

该数据内容是 JSON 对象的集合, 文件的每一行都是一个JSON 对象, 比较膈应没法直接使用 Pandas 的 read_json, 需要走一个弯路

import pandas as pd
import json
import matplotlib.pyplot as plt
%matplotlib inline

# 数据的路径, 自行从 github 下载到本地
data_path = '/foo/bar/data.txt'
# 将数据逐行解析
json_data = [json.loads(line) for line in open(data_path, 'r')]
# 转化为 DataFrame 格式
df = pd.DataFrame(json_data)

统计每个时区的数量

df的"tz" (time zone)字段表示的是该记录来自哪个时区, 下面使用 pandas 进行统计

# 先进行数据清洗, 填充缺失值 (空值)
clean_tz = df['tz'].fillna('Missing')
# 填充空字符串
clean_tz[clean_tz == ''] = 'Unkown'
# 将TOP10画出来, 其中 rot 参数表示 Label 旋转的角度, rotation 的缩写
clean_tz.value_counts().head(10).plot(kind = 'barh', rot = 0)

Pandas (一): 基本操作

统计浏览器信息

df的"a"(agent) 字段表示用户所使用的浏览器等详细信息, 可以通过截取它的第一个单词获得其浏览器的种类

agents = pd.Series([a.split(' ')[0].split('/')[0] for a in df['a'].fillna('Unkown')])
agents.value_counts().head(5).plot(kind = 'barh', rot = 0)

Pandas (一): 基本操作

同时可以从df[‘a’]中得到操作系统的信息, 下面统计windows操作系统的分布

clean_a = df['a'].fillna('Unkown')
op_sys = np.where(clean_a.str.contains('Windows'), 'Windows', 'Other')
tz_os = df.replace('', 'Unkown').groupby(['tz', op_sys])
tz_os = tz_os.size().unstack().fillna(0)
indexer = tz_os.sum(1).argsort()
count_subset = tz_os.take(indexer)[-6:]
normed_subset = count_subset.div(count_subset.sum(1), axis = 0)
normed_subset.plot(kind = 'barh', stacked = True)

Pandas (一): 基本操作

1880-2010 全美婴儿姓名

加载所有数据

base_path = '/foo/bar'
import os
def get_csv(year):
    file_name = os.path.join(base_path, 'yob%d.txt' % year)
    return pd.read_csv(file_name, names = ['name', 'sex', 'births'])

def get_all(years):
    res = []
    for year in years:
        df = get_csv(year)
        df['year'] = year
        res.append(df)
    return pd.concat(res, ignore_index = True)

years = range(1880, 2011)
data = get_all(years)

统计性别趋势

pivot table 真是个好东西, 它将数据按照自己想要的维度来重新排列, 比如现在要统计两个性别的出生数量的趋势, 那么可以以年份为行, 性别为列, 出生量的和为一个值, 每一列数据为一组, 即经过上述规则组织的数据表示男性每年的出生总量和女性每年的出生总量

def plot_name_trend(names):
    res = data.pivot_table('births', index = 'year', columns = 'name', aggfunc = np.sum)
    res[names].plot(title = 'Birth trend for name %s' % str.join(',', names))
    
plot_name_trend(['Ali', 'Anna', 'Alex', 'Gina'])

Pandas (一): 基本操作

统计姓名趋势

def plot_name_trend(names):
    res = data.pivot_table('births', index = 'year', columns = 'name', aggfunc = np.sum)
    res[names].plot(title = 'Birth trend for name %s' % str.join(',', names))
    
plot_name_trend(['Ali', 'Anna', 'Alex', 'Gina'])

Pandas (一): 基本操作

总结

使用 Pandas 是数据科学领域的基本功, 之前在知乎和CSDN上看到了很多探索数据的教程, 在看这本书之前还觉得他们很厉害, 从各种角度各种分析, 但是在学过之后才发现他们的方法都好笨, 比如如果想要在 Kaggle 的 Titanic 中查看Pclass & Sex对于生存的分布时, 使用 pivot table 的方法代码如下

df.pivot_table('Count', index = ['Pclass', 'Sex'], columns = ['Survived'], aggfunc = np.sum).plot(kind = 'bar', stacked = True)

Pandas (一): 基本操作

seaborn 的方式如下:

label = []
for sex_i in ['female','male']:
    for pclass_i in range(1,4):
        label.append('sex:%s,Pclass:%d'%(sex_i, pclass_i))
        
pos = range(6)
fig = plt.figure(figsize=(16,4))
ax = fig.add_subplot(111)
ax.bar(pos, 
        train[train['Survived']==0].groupby(['Sex','Pclass'])['Survived'].count().values, 
        color='r', 
        alpha=0.5, 
        align='center',
        tick_label=label, 
        label='dead')
ax.bar(pos, 
        train[train['Survived']==1].groupby(['Sex','Pclass'])['Survived'].count().values, 
        bottom=train[train['Survived']==0].groupby(['Sex','Pclass'])['Survived'].count().values,
        color='g',
        alpha=0.5,
        align='center',
        tick_label=label, 
        label='alive')
ax.tick_params(labelsize=15)
ax.set_title('sex_pclass_survived', size=30)
ax.legend(fontsize=15,loc='best')

Pandas (一): 基本操作

所以先看书真的能省很多事