Python 在数据科学领域越来越流行了。它的流行不无道理。 Python 容易学,有超强数据科学库,并且和 Hadoop 以及 Spark 等数据库和工具整合得非常好。Python 可以从头至尾完成一个数据科学项目,无论是读取数据、分析数据、数据可视化还是用机器学习来做预测都可以。
本文介绍如何用Python 上手数据科学。如果想要了解更多内容请访问Dataquest, 那里有使用 Python 完成数据科学任务的深入讲解。
本文使用的是关于2016 美国总统大选政治资助的数据集(链接在此)。文件是 csv 格式,每行代表对一个候选人的一次捐赠。这个数据集有几列比较值得一提,比如:
cand_nm
– 接受捐赠的候选人姓名contbr_nm
– 捐赠人姓名contbr_state
– 捐赠人所在州contbr_employer
– 捐赠人所在公司contbr_occupation
– 捐赠人职业contb_receipt_amount
– 捐赠数额(美元)contb_receipt_dt
– 收到捐款的日期
安装 Python
要分析这些数据,首先要安装 Python。利用Anaconda这个工具来安装 Python 是非常简单的。Anaconda 在安装 Python 的同时还会安装一些流行的数据分析库。点击这里下载 Anaconda。建议安装最新的 Python 3.5 版本。这个链接里介绍了一些 Python 2 与 Python 3 的对比。
Anaconda 会自动安装一些这篇文章会用到的库,包括Jupyter、Pandas、scikit-learn和matplotlib。
Jupyter 入门
都安装好之后可以启动 Jupyter notebook (原名 IPython notebook)。Jupyter notebook 是个强有力的数据分析工具。它能够帮助快速查看数据、将结果可视化以及把结果分享给他人。谷歌、IBM、微软的数据科学家都用它来分析数据以及组内协作。
在命令行里输入ipython notebook
来运行 Jupyter。如果遇到问题可以去它的官方文档里查找答案。
启动后会出现一个可以查看文件的浏览器界面,在这个页面上可以创建新的 notebook。请创建一个叫 Python 3 的 notebook,一会儿的数据分析中会用到它。如果刚才的安装还没成功,这篇文章也许有帮助。
Notebook 工作区块
每个 Jupyter notebook 都包含多个区块(cell),区块可以运行代码也可以只包含文档。每个 notebook 开始时都自带一个区块,如有需要可以自行增加多个区块,比如:
In[]:
Python
1 2 3 4 |
# 代码区块示例。产生的输出会在下方显示。 print(10) b = 10 |
In[]:
Python
1 2 3 4 |
# 可以建立多个区块,每个代码区块可以根据分析的需求跑任意次 # Jupyter notebook 中一个很赞的功能是每个区块跑出来的结果会被缓存起来, 这样一个区块可以利用另一个区块跑出来的结果。 print(b * 10) |
如果想要了解更多关于 Jupyter 的知识请阅读作者提供的更深入的教程。
Pandas 入门
Pandas是 Python 上的一个数据分析库。它能读取包括 csv 在内的不同格式的数据,分析数据也很有效。可以通过下面的代码来读取数据:
In[2]:
Python
1 2 3 |
import pandas as pd donations = pd.read_csv(“political_donations.csv”) |
In[3]:
1 |
donations.shape |
Out[3]:
1 |
(384885, 18) |
In[4]:
Python
1 |
donations.head(2) |
Out[4]:
续上表
上面的区块用import pandas as pd
这个语句导入了 Pandas 库,然后用read_csv()这个函数把political_donations.csv
这个文件读入了变量donations
中。变量donations
现在就是一个 PandasDataFrame。PandasDataFrame可以被看做是加强版的矩阵,它自带数据分析函数,并且允许不同的列包含不同的数据类型。
可以通过变量donations
的 shape
属性来打印它多少行多少列。每个区块的最后一行语句或变量都会自动显示,这个功能超赞!下一个区块用了 DataFrames 的head() 函数打印出了变量donations
的头两行,这样就能看里面的数据了。
如想更深入地了解 Pandas 请参阅作者提供的课程。
每个候选人收到的捐款总额
使用Pandas 中的 groupby()函数能计算出每个候选人的整体统计数据。根据变量cand_nm
(候选人姓名)来把变量 donations
分成不同的子集就可以针对每个候选人分别统计数据。首先要算的是捐款总额。把候选人的contb_receipt_amount
这一列加起来就可以得到收到的捐款总额了。
In[14]:
Python
1 |
donations.groupby(“cand_nm”).sum().sort(“contb_receipt_amt”) |
Out[14]:
contb_receipt_amt | file_num | |
---|---|---|
cand_nm | ||
Pataki, George E. | 365090.98 | 234695430 |
Webb, James Henry Jr. | 398717.25 | 709419893 |
Lessig, Lawrence | 621494.50 | 1378488449 |
Santorum, Richard J. | 781401.03 | 822086638 |
Trump, Donald J. | 1009730.97 | 2357347570 |
Jindal, Bobby | 1013918.12 | 584896776 |
Perry, James R. (Rick) | 1120362.59 | 925732125 |
Huckabee, Mike | 1895549.15 | 2700810255 |
O’Malley, Martin Joseph | 2921991.65 | 2664148850 |
Graham, Lindsey O. | 2932402.63 | 3131180533 |
Kasich, John R. | 3734242.12 | 2669944682 |
Christie, Christopher J. | 3976329.13 | 2421473376 |
Paul, Rand | 4376828.14 | 16056604577 |
Fiorina, Carly | 4505707.06 | 12599637777 |
Walker, Scott | 4654810.30 | 5636746962 |
Sanders, Bernard | 9018526.00 | 71139864714 |
Rubio, Marco | 10746283.24 | 22730139555 |
Carson, Benjamin S. | 11746359.74 | 75613624360 |
Cruz, Rafael Edward ‘Ted’ | 17008622.17 | 69375616591 |
Bush, Jeb | 23243472.85 | 14946097673 |
Clinton, Hillary Rodham | 61726374.09 | 86560202290 |
上面的代码首先用donations.groupby("cand_nm")
根据cand_nm
把donations
分成了不同的组。这个语句返回的是GroupBy 对象,GroupBy 类型自带一些专门用来整合数据的函数。其中就包含sum()
函数,在这个问题中可以用来计算每组中每一列中数据的和。
Pandas 在读取数据的时候就会自动识别每一列的数据类型,在进行求和时只会针对数字类型的列来操作。这样就得到了一个包含每个候选人contb_receipt_amt
列中所有数字之和及file_num
列中所有数字之和的 DataFrame。最后使用 DataFrames 中的sort() 函数将contb_receipt_amt
的和从小到大排序。这样就得到了每个候选人收到的捐款总额。
将捐款总额可视化
Python 中最主要的可视化包就是matplotlib,可以用它来画图。Jupyter notebook 能够在浏览器中直接渲染 matplotlib 的图表。这个功能需要通过激活 matplotlib 的 inline 模式来开启。可以利用Jupyter magics中的命令来激活它就能直接在 notebook 中看图表了。
Magics 就是以 %
或者 %%
开头的、能改变 Jupyter notebook 本身的命令。它们是为了让能够通过命令行改变 Jupyter 的设置,同时尽量不与 Python 代码混淆而存在的。要想在浏览器里直接看 matplotlib 的图表,需要在代码区块里运行 %matplotlib inline
。更多关于用 Jupyter 画图的内容可以在此阅读。
用下面的代码来导入 matplotlib
库并且开启 inline 模式:
In[15]:
Python
1 2 3 |
import matplotlib.pyplot as plt %matplotlib inline |
Pandas 中的 DataFrames 自带对可视化的支持,调用 plot() 函数就可以生成 matplotlib
图表。这么用一般会比调用 matplotlib
更方便快捷。先给之前的 DataFrame 赋值给一个变量total_donations,
再利用indexing 来选择 DataFrame 中的一列: contb_receipt_amt
。这样就生成了一个 Pandas 中的 Series 类型的变量。
Pandas 中的 Series 和 DataFrames 包含的函数都差不多,但是 Series 只能存一维数据,比如单一行或者单一列。调用 Series 的 plot() 函数就生成了一个显示每个候选人收到的捐款总额的柱状图。
In[16]:
Python
1 |
total_donations = donations.groupby(“cand_nm”).sum().sort(“contb_receipt_amt”) |
In[20]:
Python
1 |
total_donations[“contb_receipt_amt”].plot(kind=”bar”) |
Out[20]:
1 |
<matplotlib.axes._subplots.AxesSubplot at 0x108892208> |
如果想深入学习 matplotlib, 可以学习作者提供的课程。
计算捐款平均值
已经学会算捐款总额啦,再想算捐款平均值超级容易。直接用求平均值的mean()函数来替换求和用的sum()
函数就得了。
In[22]:
Python
1 2 |
avg_donations = donations.groupby(“cand_nm”).mean().sort(“contb_receipt_amt”) avg_donations[“contb_receipt_amt”].plot(kind=”bar”) |
Out[22]:
1 |
<matplotlib.axes._subplots.AxesSubplot at 0x108d82c50> |
预测捐款数目
下面来写个简单的根据一个人所在的州(contbr_st
)、职业(contbr_occupation
)及支持的候选人(cand_nm
)来预测捐款数额的简单算法吧。首先用这几列及要预测的 contb_receipt_amt
列来另外创建一个 Dataframe。
In[41]:
Python
1 |
pdonations = donations[[“contbr_st”, “contbr_occupation”, “cand_nm”, “contb_receipt_amt”]] |
下面来看看变量 pdonations
里每一列的数据类型。Pandas 读取 csv 文件时会自动给每列赋予数据类型。只有数值型(numeric)的列才能用来做预测。
In[42]:
Python
1 |
pdonations.dtypes |
Out[42]:
1 2 3 4 5 |
contbr_st object contbr_occupation object cand_nm object contb_receipt_amtfloat64 dtype: object |
倒霉的是想要用的列都是 object 型的(都是字符串)。这是因为它们都是分类数据(categorical data)。每列中有几个可能的值,但这些选项是用文本来表示的而不是用数值型代码来表示的。可以先把每列都转换成分类型(categorical),然后再转换成数值型。这里有关于分类型数据的更多介绍。本质上就是分类型数据在后台给一列中每个不同的值赋予了一个不同的数值型代号。可以将一列种的值都换成这些代号,这样一列就完全被转换成数值型的了。
In[43]:
Python
1 2 |
pdonations[“contbr_st”] = pdonations[“contbr_st”].astype(‘category’) pdonations[“contbr_st”] = pdonations[“contbr_st”].cat.codes |
In[44]:
Python
1 |
pdonations[“contbr_st”] |
Out[44]:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
0 1 1 1 2 1 3 2 4 2 5 2 7 2 8 2 9 2 102 112 122 132 142 … 38487075 38487175 38487275 38487375 38487475 38487575 38487675 38487775 38487875 38487975 38488175 38488275 38488377 38488477 Name: contbr_st, Length: 384885, dtype: int8 |
可以看到 contbr_st
列已经被转换成数值型的了。下面对 contbr_occupation
及cand_nm
两列也进行同样的操作。
In[]:
Python
1 2 3 |
for column in [“contbr_st”, “contbr_occupation”, “cand_nm”]: pdonations[column] = pdonations[column].astype(‘category’) pdonations[column] = pdonations[column].cat.codes |
训练集和测试集的拆分
接下来的预测步骤中可以利用到 Python 中最主要的机器学习包scikit-learn。首先要把数据拆分成两个部分。一部分用于训练算法,称为训练集;另一部分用于评估模型的效果,称为测试集。这样做是为了避免过拟合(overfitting)产生的有误导性的结果。
用 train_test_split() 这个函数可以将 pdonations
拆分成一个训练集和一个测试集。
In[48]:
Python
1 2 3 |
from sklearn.cross_validation import train_test_split train, test, y_train, y_test = train_test_split(pdonations[[“contbr_st”, “contbr_occupation”, “cand_nm”]], pdonations[“contb_receipt_amt”], test_size=0.33, random_state=1) |
上面的代码将训练算法需要用的列及结果列(contb_receipt_amt)中的值分成了训练集和测试集。测试集中包含33%的数据。每行数据被随机分配到训练集中或者测试集中。
拟合模型
下面会使用随机森林(random forest)算法来做预测。随机森林是一个效果比较好并且适用于很多问题的算法,在 scikit-learn 包中是通过 RandomForestRegressor类来实现的。使用这个类训练模型及用模型做预测都很简单。
首先用 train
和 y_train
来训练模型:
In[52]:
Python
1 2 3 4 5 |
from sklearn.ensemble import RandomForestRegressor model = RandomForestRegressor(n_estimators=100, min_samples_leaf=10) <div4″> <div5″>model.fit(train, y_train) |
Out[52]:
Python
1 2 3 4 5 |
RandomForestRegressor(bootstrap=True, compute_importances=None, criterion=’mse’, max_depth=None, max_features=’auto’, max_leaf_nodes=None, min_density=None, min_samples_leaf=10, min_samples_split=2, n_estimators=100, n_jobs=1, oob_score=False, random_state=None, verbose=0) |
scikit-learn 包一个优点是里面所有算法都有一致的 API。训练一个线性规划(linear regression)模型和训练一个随机森林模型用的方法是一模一样的。有了合适的模型就可以用它来做预测了。
预测及误差计算
用 scikit-learn 包做预测也非常简单。直接把测试集传给训练好的模型就行了。
In[54]:
Python
1 |
predictions = model.predict(test) |
有了预测结果之后来算算误差值。误差能体现模型的效果,在调整模型时也能作为一个衡量标准。下面会用一个常见的误差标准,均方误差(mean squared error)。
In[57]:
Python
1 2 3 4 |
from sklearn.metrics import mean_squared_error import math mean_squared_error(predictions, y_test) |
Out[57]:
1 |
756188.21680533944 |
如果想了解更多关于 scikit-learn 的知识可以阅读作者撰写的教程。
接下来做点什么
对误差求平方根得到的值和捐款额之间的关系更直观。如果不求平方根而只用平均方差 (average squared error),那它就和上面用的数据没什么直接关系。无论怎么算目前的误差值都很大,有很多减小误差的方法,比如:
- 利用上其他列中的数据
- 看看是否对每个候选人训练一个模型效果会更好
- 尝试用其他算法
还有一些有意思的对数据的探索可以做,比如:
- 找出每个州哪个候选人得到的捐款最多
- 画出对每个候选人来说,来自哪种职业的人捐的钱最多的图
- 根据候选人是民主党还是共和党划分,看看是否会有有意思的模式出现
- 通过名字给数据添加性别,看看如果根据性别划分数据是否会显现出有意思的模式
- 根据美国不同地区的捐款总额画一个热图(heatmap)
想要深入了解本文讲解到的概念,请参阅作者提供的 Python 数据科学课程。
本文由 伯乐在线 – XiaoxiaoLi 翻译,sunshinebuel 校稿。英文出处:Vik Paruchuri。
本文链接:http://python.jobbole.com/85394/
本文采用「CC BY-SA 4.0 CN」协议转载自互联网、仅供学习交流,内容版权归原作者所有,如涉作品、版权和其他问题请给「我们」留言处理。