前言
承接上篇《Python 神兵谱之数据分析-上篇:数据采集》,今天我们来讲讲这中篇:数据处理。
如果说数据采集好比战前情报收集、战略部署,那么,数据处理好比短兵相接、浴血厮杀了。俗话说,一将功成万骨枯,战斗胜利后风光无限的是一军之将,以命相博的将士往往却默默无闻。
数据处理也是如此,风光背后,是一位位数据处理工程师默默的付出,他们劈荆斩棘,他们乘风破浪。没人知道他们剔除了多少脏数据,没人知道他们变换了多少数据模型,我们看到的只是展示给我们的冰山一角的数据而已。
中篇:数据处理
说到数据处理,最大名鼎鼎的应该就是“Excel”了,它的大名,可谓无人不知,无人不晓。有了 Excel,即使毫无编程经验的人,都能对数据耍上两把。而我们今天就来看看,仅仅一点点代码,就能实现的更为强大的功能。
Numpy
第一把交椅,必须是“Numpy”了。不少人可能听说过,但是可能从未用过,因为 Numpy 是 Python 数据处理的基石,是其他不少相关工具的依赖。
Numpy 的功能非常纯粹,它为 Python 提供了一个非常强大且灵活的“数组”数据结构。
但是 Python 不是有列表(list)了吗?为什么还要其他的“数组”结构?
Numpy 主要有以下几个特点:
- list 仅仅是一个“链表”,而 Numpy 提供了真正的多维数组
- 提供了众多的数组相关操作
- 提供了许多线性代数等数学函数
- 提供了广播功能,像操作标量一样操作多维数组
- 底层使用 C 实现,非常快,适合大量数据处理
Numpy 提供了非常方便的方法生成多维数组,例如从 list 转换而来。
import numpy as np
a = np.array([1,2,3,4])
复制代码
第一行引入 Numpy,这是一般推荐的做法,用 as 别名为 np。不是必须的,但建议遵循。
还有众多的生成函数。
# 生成一个 3 * 4 的矩阵,每个元素都是 0
np.zeros((3,4))
# 生成一个 2 * 3 的矩阵,每个元素都是 1
np.ones( (2,3) )
# 等差数列生成,从 10 到 30,5 递增
np.arange(10, 30, 5)
复制代码
不同于 list,数组的每个元素必须有一致的数据类型。
>>> a.dtype.name
'int64'
复制代码
可以在创建时通过 dtype 参数指定,例如 int32,int64,float64 等。
Numpy 的数组有几个比较重要的属性。
- ndim:轴的数量,也就是维度
- shape:数组大小的元祖
- size:总数据个数
- dtype:数据类型
- itemsize:每个数组元素占的字节数
# 创建一个 1 到 14 到数组,并改成 3 * 5 的矩阵
>>> a = np.arange(15).reshape(3, 5)
>>> a
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
>>> a.ndim
2
>>> a.shape
(3, 5)
>>> a.size
15
>>> a.dtype.name
'int64'
>>> a.itemsize
8
复制代码
这还是牛刀小试,让我们来见识 Numpy 的实力吧,像操作普通标量一样操作数组。
# 数组每个元素乘以 2
>>> b = a * 2
>>> b
array([[ 0, 2, 4, 6, 8],
[10, 12, 14, 16, 18],
[20, 22, 24, 26, 28]])
# 数组对应元素相加
>>> a + b
array([[ 0, 3, 6, 9, 12],
[15, 18, 21, 24, 27],
[30, 33, 36, 39, 42]])
# 数组对应元素相乘
>>> a * b
array([[ 0, 2, 8, 18, 32],
[ 50, 72, 98, 128, 162],
[200, 242, 288, 338, 392]])
# 逻辑判断,每个元素是否小于 8
>>> a < 8
array([[ True, True, True, True, True],
[ True, True, True, False, False],
[False, False, False, False, False]], dtype=bool)
复制代码
基本的函数操作
>>> a
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
# 纵向求和(轴索引为 0)
>>> a.sum(axis=0)
array([15, 18, 21, 24, 27])
# 横向求和(轴索引为 1)
>>> a.sum(axis=1)
array([10, 35, 60])
# 每行的最小值(轴索引为 1)
>>> a.min(axis=1)
array([ 0, 5, 10])
复制代码
取数据
# 取索引 0,0 处的元素,也就是第一行第一个
>>> a[0,0]
0
# 取索引 2,3 处的元素
>>> a[2,3]
13
复制代码
当然也可以切片操作
# 取索引为 1 到 2 (不含)的行,也就是第 2 行
>>> a[1:2]
array([[5, 6, 7, 8, 9]])
# 取索引为 1 到 3 (不含)的行,索引为 2 到 5(不含)的列
>>> a[1:3,2:5]
array([[ 7, 8, 9],
[12, 13, 14]]))
复制代码
还有其他的数组转换、线性代数计算等函数,就不详细展开了。Numpy 就是我们进行数据处理的基本容器,有了 Numpy 提供的数组结构,后面的操作就游刃有余了。
Scipy
Scipy 是数学、工程、科学计算相关的函数库,本身是基于 Numpy 的数组的,也是和 Numpy 师出同门。
Scipy 有许多子模块,每个子模块提供各个领域特定的功能。
- cluster:聚类算法
- constants:物理和数学的常量
- fftpack:快速傅立叶变换
- integrate:微积分方程求解
- interpolate:插值计算
- io:输入输出
- linalg:线性代数
- ndimage:n 维图像处理
- ord:正交距离回归
- optimize:优化
- signal:信号处理
- sparse:稀疏矩阵
- spatial:空间数据结构和算法
- special:特殊函数
- stats:统计分布函数
各个函数的使用需要一定的理论基础,scipy 已经帮助我们实现,只需要调用即可。
例如,我们计算如下的积分方程
>>> import scipy.integrate as integrate
>>> import scipy.special as special
>>> result = integrate.quad(lambda x: special.jv(2.5,x), 0, 4.5)
>>> result
(1.1178179380783249, 7.8663172481899801e-09)
复制代码
是不是再也不怕高数作业了?
Pandas
Pandas 不是一只普通的熊猫。Pandas 是基于 Numpy 的高级的数据处理工具库。Pandas 最擅长的就是处理表格数据,也就是我们熟悉的 Excel 类型的数据,Pandas 提供的方法能让我们简单的几行代码快速处理类 Excel 或者关系型数据表的数据。
一个最简单的例子。
>>> import pandas as pd # 和 nunpy 一样的约定,一般引入后别名为 pd
>>> df = pd.read_csv('test.csv') # 读取 csv 文件
>>> df # 显示读取的内容,为两列三行的数据
name price
0 apple 5
1 banana 3
2 pear 2
>>> df.describe() # 查看数据统计,自动找出数据列(price),计算相关统计量
price
count 3.000000
mean 3.333333
std 1.527525
min 2.000000
25% 2.500000
50% 3.000000
75% 4.000000
max 5.000000
>>> df.price = df.price * 2 # 所有价格都乘以 2
>>> df
name price
0 apple 10
1 banana 6
2 pear 4
>>> df.to_csv('out.csv', index=False) # 导出数据到 csv 文件
复制代码
Pandas 可以用来做数据清洗、转换、聚合等操作,为下一步数据可视化及机器学习准备数据。
Pandas 有多种数据类型,其中就常见的两种就是 Series 和 DataFrame。
DataFrame 可以理解为一个数据表格,行有行的标签(索引),列有列的标签(索引),是不是和 Excel 很像?
而 Series 即是这个数据表格的一列或者一行。所以一个 DataFrame 也可看作是一个 Series 数组。
Pandas 提供了一系列的方法快速的从其他数据源导入导出数据。
Pandas 也能非常方便的“挑选”特定的数据。
通过 Matplotlib 库,Pandas 可以方便的绘制可视化图表。
对于基本的数据抽取、转换、清洗等工作,Pandas 完全能胜任,掌握了 Pandas 就有了应对各种敌人的百变战甲。
Scikit-Learn
Scikit-Learn 是 Python 的机器学习库,也是在 Numpy 和 Scipy 的基础上,提供了强大的机器学习算法的实现。例如分类算法(SVM,K 近邻,随机森林等),回归算法(线性回归、SVR 等),聚类算法(K-means、谱聚类等)、降维、模型选择、数据预处理等等。
Scikit-Learn 通过对算法的高度抽象,对于一个基本的算法调用过程,基本上就简化为了:初始化->数据预处理->训练->预测,流程中的几个步骤。
一个简单的线性回归的例子。
>>> from sklearn import linear_model
>>> reg = linear_model.LinearRegression()
>>> reg.fit([[0, 0], [1, 1], [2, 2]], [0, 1, 2])
LinearRegression()
>>> reg.coef_
array([0.5, 0.5])
复制代码
除了基本的算法实现,scikit-learn 提供的数据预处理也极其强大,基本能涵盖数据预处理的许多方面。
例如,数据归一化,快速的 Z-score 归一化,使数据满足正态分布。
>>> from sklearn import preprocessing
>>> import numpy as np
>>> X_train = np.array([[ 1., -1., 2.],
... [ 2., 0., 0.],
... [ 0., 1., -1.]])
>>> X_scaled = preprocessing.scale(X_train)
>>> X_scaled
array([[ 0. ..., -1.22..., 1.33...],
[ 1.22..., 0. ..., -0.26...],
[-1.22..., 1.22..., -1.06...]])
复制代码
数据编码,可以将枚举的字符串数据编码为数值型,方便后续计算。
>>> X = [['male', 'from US', 'uses Safari'], ['female', 'from Europe', 'uses Firefox']]
>>> enc.fit(X)
OrdinalEncoder()
>>> enc.transform([['female', 'from US', 'uses Safari']])
array([[0., 1., 1.]])
复制代码
One Hot 编码,将枚举字符串数据转换为多列的布尔数据(0 / 1)。
>>> X = [['male', 'from US', 'uses Safari'], ['female', 'from Europe', 'uses Firefox']]
>>> enc.fit(X)
OneHotEncoder()
>>> enc.transform([['female', 'from US', 'uses Safari'],
... ['male', 'from Europe', 'uses Safari']]).toarray()
array([[1., 0., 0., 1., 0., 1.],
[0., 1., 1., 0., 0., 1.]])
复制代码
缺失值处理。
>>> import numpy as np
>>> from sklearn.impute import SimpleImputer
>>> imp = SimpleImputer(missing_values=np.nan, strategy='mean')
>>> imp.fit([[1, 2], [np.nan, 3], [7, 6]])
SimpleImputer()
>>> X = [[np.nan, 2], [6, np.nan], [7, 6]]
>>> print(imp.transform(X))
[[4. 2. ]
[6. 3.666...]
[7. 6. ]]
复制代码
如果想要看一个实战的项目,这里有一个基因型预测身高的项目例子。该项目根据用户在多个基因位点的基因型和身高数据进行模型训练,然后可根据训练的模型预测其他用户的身高。我们先不管这个预测的理论可行性和准确性,不过整个数据预处理和模型训练的操作是一个学习 scikit-learn 的过程。
Statsmodels
statsmodels 是一个 Python 的统计模型库,提供了很多统计相关的函数和操作,例如线性回归、统计检验、时间序列分析等。statsmodels 也是构建在 Numpy、SciPy 和 Pandas 之上的。
线性回归模型
import statsmodels.api as sm
data = sm.datasets.scotland.load(as_pandas=False) # 载入测试数据
data.exog = sm.add_constant(data.exog)
# 实例化伽马模型
>>> gamma_model = sm.GLM(data.endog, data.exog, family=sm.families.Gamma())
>>> gamma_results = gamma_model.fit()
>>> print(gamma_results.summary())
Generalized Linear Model Regression Results
==============================================================================
Dep. Variable: y No. Observations: 32
Model: GLM Df Residuals: 24
Model Family: Gamma Df Model: 7
Link Function: inverse_power Scale: 0.0035843
Method: IRLS Log-Likelihood: -83.017
Date: Fri, 21 Feb 2020 Deviance: 0.087389
Time: 13:59:13 Pearson chi2: 0.0860
No. Iterations: 6
Covariance Type: nonrobust
==============================================================================
coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------
const -0.0178 0.011 -1.548 0.122 -0.040 0.005
x1 4.962e-05 1.62e-05 3.060 0.002 1.78e-05 8.14e-05
x2 0.0020 0.001 3.824 0.000 0.001 0.003
x3 -7.181e-05 2.71e-05 -2.648 0.008 -0.000 -1.87e-05
x4 0.0001 4.06e-05 2.757 0.006 3.23e-05 0.000
x5 -1.468e-07 1.24e-07 -1.187 0.235 -3.89e-07 9.56e-08
x6 -0.0005 0.000 -2.159 0.031 -0.001 -4.78e-05
x7 -2.427e-06 7.46e-07 -3.253 0.001 -3.89e-06 -9.65e-07
==============================================================================
复制代码
方差分析
>>> import statsmodels.api as sm
>>> from statsmodels.formula.api import ols
>>> moore = sm.datasets.get_rdataset("Moore", "carData", cache=True) # 载入测试数据
>>> data = moore.data
>>> data = data.rename(columns={"partner.status": "partner_status"}) # 重命名
>>> moore_lm = ols('conformity ~ C(fcategory, Sum)*C(partner_status, Sum)', data=data).fit()
>>> table = sm.stats.anova_lm(moore_lm, typ=2) # Type 2 ANOVA DataFrame
>>> print(table)
sum_sq df F PR(>F)
C(fcategory, Sum) 11.614700 2.0 0.276958 0.759564
C(partner_status, Sum) 212.213778 1.0 10.120692 0.002874
C(fcategory, Sum):C(partner_status, Sum) 175.488928 2.0 4.184623 0.022572
Residual 817.763961 39.0 NaN NaN
复制代码
XGBoost
XGBoost 是一个改进的梯度增强算法(gradient boosting),基本的梯度增强算法(GBDT)已经在 scikit-learn 中有了实现。而 XGBoost 改进了该算法,提供了分布式的能力,更快速,更灵活,更便携。由于 XGBoost 的简单易学,性能高效和表现优异,常常被用于各种数据科学算法大赛。例如,著名的 Kaggle 大赛,XGBoost 是许多竞赛的夺冠热门算法。
XGBoost 是一个算法的名称,但是提供众多语言的实现,例如 Python, R, Java, Scala, C++ 等,同时也支持 Hadoop,Spark 等大数据生态。
如果需要详细了解 GBDT 和 XGBoost 的前世今生,可以戳这篇文章。
这里还有几个 Kaggle 竞赛项目的具体例子,可以供大家直接学习。
后记
当然,数据处理的方式和算法实在是太多了,各种优化的算法库也是层出不穷,还有不少 BI 软件和商业化的工具。这里展示的几个算是这个领域中最大名鼎鼎的几件大杀器,大杀器在手,虾兵蟹将绕着走!
百媚生 Python《神兵谱》之数据分析-中篇,如果觉得有用,请点赞关注收藏哦!