跟着教程学习了一段时间数据分析,越学感觉坑越多。于是花了一个星期仔细看了下《利用Python进行数据分析》。写在这里主要是记录下,方便自己查看。
import numpy as np import pandas as pd import patsy
# 利用Patsy创建模型描述 Patsy是一个python库,用于描述统计模型(尤其是线性模型),方法是通过一个叫做公式语法(formula syntax)的字符串来描述。这种公式语法的灵感来源于R和S语言中的公式语法。 Patsy的公式是有特殊格式的字符串,像下面这样: y ~ x0 + x1 这种a + b的语法并不代表将a和b相加,而是代表为模型创建的设计矩阵的术语(terms in the design matrix)。patsy.dmatrices函数,取一个公式字符串和一个数据集(可以使DataFrame或dict),然后为线性模型产生设计矩阵:
data = pd.DataFrame({'x0': [1, 2, 3, 4, 5], 'x1': [0.01, -0.01, 0.25, -4.1, 0.], 'y': [-1.5, 0., 3.6, 1.3, -2.]}) data
y, X = patsy.dmatrices('y ~ x0 + x1', data) y
DesignMatrix with shape (5, 1) y -1.5 0.0 3.6 1.3 -2.0 Terms: 'y' (column 0)
X
DesignMatrix with shape (5, 3) Intercept x0 x1 1 1 0.01 1 2 -0.01 1 3 0.25 1 4 -4.10 1 5 0.00 Terms: 'Intercept' (column 0) 'x0' (column 1) 'x1' (column 2)
这些Patsy DesignMatrix实例是Numpy的ndarrays,附有额外的元数据(metadata)
np.asarray(y) array([[-1.5], [ 0. ], [ 3.6],[ 1.3],[-2. ]])
np.asarray(X) array([[ 1. , 1. , 0.01],[ 1. , 2. , -0.01],[ 1. , 3. , 0.25],[ 1. , 4. , -4.1 ],[ 1. , 5. , 0. ]])
我们可能奇怪X中的Intercept是从哪里来的。这其实是线性模型的一个惯例,比如普通最小二乘回归法(ordinary least squares regression)。我们可以去掉这个截距(intercept),通过加添术语+0给模型
patsy.dmatrices('y ~ x0 + x1 + 0', data)[1]
DesignMatrix with shape (5, 2) x0 x1 1 0.01 2 -0.01 3 0.25 4 -4.10 5 0.00 Terms: 'x0' (column 0) 'x1' (column 1)
这种Patsy对象可以直接传入一个算法,比如numpy.linalg.lstsq,来进行普通最小二乘回归的计算
# 最小二乘法 coef, resid, _, _ = np.linalg.lstsq(X, y, rcond=-1) coef
array([[ 0.31290976], [-0.07910564], [-0.26546384]])
coef = pd.Series(coef.squeeze(), index=X.design_info.column_names) coef
Intercept 0.312910 x0 -0.079106 x1 -0.265464 dtype: float64
1、Patsy公式的数据变换
我们可以把python和Patsy公式混合起来。当评估公式的时候,库会尝试找到封闭域中的公式:
y, X = patsy.dmatrices('y ~ x0 + np.log(np.abs(x1) + 1)', data) X
DesignMatrix with shape (5, 3) Intercept x0 np.log(np.abs(x1) + 1) 1 1 0.00995 1 2 0.00995 1 3 0.22314 1 4 1.62924 1 5 0.00000 Terms: 'Intercept' (column 0) 'x0' (column 1) 'np.log(np.abs(x1) + 1)' (column 2)
一些常用的变量变换,包括标准化(standardizing (平均值0,方差1)和中心化(减去平均值)。Patsy有内建的函数可以做到这些
y, X = patsy.dmatrices('y ~ standardize(x0) + center(x1)', data) X
DesignMatrix with shape (5, 3) Intercept standardize(x0) center(x1) 1 -1.41421 0.78 1 -0.70711 0.76 1 0.00000 1.02 1 0.70711 -3.33 1 1.41421 0.77 Terms: 'Intercept' (column 0) 'standardize(x0)' (column 1) 'center(x1)' (column 2)
作为建模的一部分,我们可能会在一个数据及上训练模型,然后在另一个数据及上评价模型。当使用中心化或标准化这样的转换时,我们必须注意,必须用模型在新数据集上做预测。这叫做状态变换(stateful transformations)。因为我们必须用原本在训练集上得到的平均值和标准差,用在新的数据集上。
通过保存原先数据集中的信息,patsy.build_design_matrices函数能把变换用在新的数据集上
new_data = pd.DataFrame({ 'x0': [6, 7, 8, 9], 'x1': [3.1, -0.5, 0, 2.3], 'y': [1, 2, 3, 4]}) new_X = patsy.build_design_matrices([X.design_info], new_data) new_X
[DesignMatrix with shape (4, 3) Intercept standardize(x0) center(x1) 1 2.12132 3.87 1 2.82843 0.27 1 3.53553 0.77 1 4.24264 3.07 Terms: 'Intercept' (column 0) 'standardize(x0)' (column 1) 'center(x1)' (column 2)]
因为加号在Patsy公式中不代表加法,如果想要把两个列通过名字相加,必须把他们用I函数包起来
y, X = patsy.dmatrices('y ~ I(x0 + x1)', data) X
DesignMatrix with shape (5, 2) Intercept I(x0 + x1) 1 1.01 1 1.99 1 3.25 1 -0.10 1 5.00 Terms: 'Intercept' (column 0) 'I(x0 + x1)' (column 1)
Patsy有一些其他的内建转换,得来patsy.builtins模块里。更多的信息请参考文档。
Categorical数据有特殊的类用于变换,下面进行介绍。
2、Categorical数据和Patsy
非数值型数据可以通过很多种方式变为一个模型设计矩阵。这个话题很大,这里只做简单介绍。
当我们在Patsy公式中使用非数值术语时,这些类型数据默认会被转换为哑变量。如果有截距,一个层级上的截距会被舍弃,防止出现共线性:
data = pd.DataFrame({'key1': ['a', 'a', 'b', 'b', 'a', 'b', 'a', 'b'], 'key2': [0, 1, 0, 1, 0, 1, 0, 0], 'v1': [1, 2, 3, 4, 5, 6, 7, 8], 'v2': [-1, 0, 2.5, -0.5, 4.0, -1.2, 0.2, -1.7] }) y, X = patsy.dmatrices('v2 ~ key1', data) X
DesignMatrix with shape (8, 2) Intercept key1[T.b] 1 0 1 0 1 1 1 1 1 0 1 1 1 0 1 1 Terms: 'Intercept' (column 0) 'key1' (column 1)
如果从模型中舍弃截距,每个类型的列会被包含在模型设计矩阵中
y, X = patsy.dmatrices('v2 ~ key1 + 0', data) X
DesignMatrix with shape (8, 2) key1[a] key1[b] 1 0 1 0 0 1 0 1 1 0 0 1 1 0 0 1 Terms: 'key1' (columns 0:2)
数值型列可以通过C函数,变为类型列:
y, X = patsy.dmatrices('v2 ~ C(key2)', data) X
DesignMatrix with shape (8, 2) Intercept C(key2)[T.1] 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 0 Terms: 'Intercept' (column 0) 'C(key2)' (column 1)
当我们在一个模型中使用多个类型术语时,会变得更复杂一些,之前用key1:key2的形式来包含有交集的术语,这种方法可以用于使用多个术语,例如,一个方法分析模型(analysis of variance (ANOVA) models):
data['key2'] = data['key2'].map({0: 'zero', 1: 'one'}) data
y, X = patsy.dmatrices('v2 ~ key1 + key2', data) X
DesignMatrix with shape (8, 3) Intercept key1[T.b] key2[T.zero] 1 0 1 1 0 0 1 1 1 1 1 0 1 0 1 1 1 0 1 0 1 1 1 1 Terms: 'Intercept' (column 0) 'key1' (column 1) 'key2' (column 2)
y, X = patsy.dmatrices('v2 ~ key1 + key2 + key1:key2', data) X
DesignMatrix with shape (8, 4) Intercept key1[T.b] key2[T.zero] key1[T.b]:key2[T.zero] 1 0 1 0 1 0 0 0 1 1 1 1 1 1 0 0 1 0 1 0 1 1 0 0 1 0 1 0 1 1 1 1 Terms: 'Intercept' (column 0) 'key1' (column 1) 'key2' (column 2) 'key1:key2' (column 3)