如何从分类变量创建交互设计矩阵?
我之前主要用R语言做统计建模和机器学习,现在想提高自己的Python技能。我想知道在Python中,如何高效地创建一个包含分类变量交互作用的设计矩阵(可以是任意程度的交互)。
举个简单的例子:
import pandas as pd
from urllib import urlopen
page = urlopen("http://www.shatterline.com/MachineLearning/data/tennis_anyone.csv")
df = pd.read_csv(page)
df.head(n=5)
假设我们想要创建Outlook(天气情况)、Temp(温度)和Humidity(湿度)之间的交互作用。有没有什么高效的方法可以做到这一点?我可以在pandas中手动做一些类似的操作:
OutTempFact=pd.Series(pd.factorize(pd.lib.fast_zip([df.Outlook.values, df.Temperature.values]))[0],name='OutTemp')
OutHumFact=pd.Series(pd.factorize(pd.lib.fast_zip([df.Outlook.values, df.Humidity.values]))[0],name='OutHum')
TempHumFact=pd.Series(pd.factorize(pd.lib.fast_zip([df.Temperature.values, df.Humidity.values]))[0],name='TempHum')
IntFacts=pd.concat([OutTempFact,OutHumFact,TempHumFact],axis=1)
IntFacts.head(n=5)
然后我可以把这个结果传给scikit-learn的独热编码器,但我觉得可能还有更好的方法,可以更少地手动操作,直接创建分类变量之间的交互,而不需要逐一处理每种组合。
import sklearn as sk
enc = sk.preprocessing.OneHotEncoder()
IntFacts_OH=enc.fit_transform(IntFacts)
IntFacts_OH.todense()
2 个回答
现在我遇到了一个类似的问题,想要找到一种简单的方法,把文献中基线OLS模型的特定交互作用整合进来,以便与机器学习的方法进行比较。于是我发现了 patsy (http://patsy.readthedocs.io/en/latest/overview.html)和这个与scikit-learn集成的 patsylearn (https://github.com/amueller/patsylearn)。
下面是如何将交互变量传递给模型的示例:
from patsylearn import PatsyModel
model = PatsyModel(sk.linear_model.LinearRegression(), "Play-Tennis ~ C(Outlook):C(Temperature) + C(Outlook):C(Humidity) + C(Outlook):C(Wind)")
需要注意的是,在这个公式中,你不需要使用 OneHotEncoder(),因为公式中的 C 告诉 Patsy 解释器这些是分类变量,它会自动为你进行独热编码!不过可以在他们的文档中了解更多信息(http://patsy.readthedocs.io/en/latest/categorical-coding.html)。
或者,你也可以使用 PatsyTransformer,我更喜欢这种方式,因为它可以很方便地集成到 scikit-learn 的管道中:
from patsylearn import PatsyTransformer
transformer = PatsyTransformer("C(Outlook):C(Temperature) + C(Outlook):C(Humidity) + C(Outlook):C(Wind)")
如果你在设计矩阵上使用了 OneHotEncoder
来得到一个独热编码的设计矩阵,那么交互项其实就是列之间的乘法。如果 X_1hot
是你的独热编码设计矩阵,其中样本是行,那么对于二阶交互项,你可以这样写:
X_2nd_order = (X_1hot[:, np.newaxis, :] * X_1hot[:, :, np.newaxis]).reshape(len(X_1hot), -1)
这样会出现重复的交互项,并且还会包含原始特征。
如果你想要更高阶的交互项,设计矩阵的规模会急剧增加。如果你真的想这样做,可以考虑使用多项式核,这样可以轻松处理任意阶数的交互项。
根据你提供的数据框,我们可以按以下步骤进行。首先,手动从数据框构建一个独热编码设计:
import numpy as np
indicators = []
state_names = []
for column_name in df.columns:
column = df[column_name].values
one_hot = (column[:, np.newaxis] == np.unique(column)).astype(float)
indicators.append(one_hot)
state_names = state_names + ["%s__%s" % (column_name, state) for state in np.unique(column)]
X_1hot = np.hstack(indicators)
列名会存储在 state_names
中,而指示矩阵是 X_1hot
。接下来,我们计算二阶特征:
X_2nd_order = (X_1hot[:, np.newaxis, :] * X_1hot[:, :, np.newaxis]).reshape(len(X_1hot), -1)
为了知道二阶矩阵的列名,我们可以这样构建它们:
from itertools import product
one_hot_interaction_names = ["%s___%s" % (column1, column2)
for column1, column2 in product(state_names, state_names)]