问题描述
我正在尝试使用有监督的机器学习来根据它们各自的长度和宽度度量来预测农作物(例如土豆)的重量。在拟合特定模型之前(例如线性回归),我想根据数据集中特定作物品种的频率对特征进行分层抽样。例如,如果我将数据分为5个分区(即使用交叉验证),并且variant1占我的观察值的50%,则每个分区训练集中的观察值中的50%应对应于variant1。这是我使用sklearn(0.23版)在Python中尝试过的代码:
import numpy as np
import pandas as pd
from sklearn.model_selection import StratifiedShuffleSplit
from sklearn.model_selection import cross_val_predict
from sklearn.linear_model import LinearRegression
# build pd.DataFrame
varieties = np.concatenate([np.repeat("variety1",10),np.repeat("variety2",30),np.repeat("variety3",60)])
columns = {"variety": varieties,"length": np.random.randint(30,70,size=100),"width": np.random.randint(40,50,"weight": np.random.random(100)*100 + 50}
df = pd.DataFrame(columns)
# stratified sampling
kf = StratifiedShuffleSplit(n_splits=5,test_size=0.2)
# fit model based on a cv splitter
lm = LinearRegression()
X = df.loc[:,"length":"width"]
y = df["weight"]
y_pred = cross_val_predict(lm,X,y,cv=kf.split(X,df["variety"]))
ValueError: cross_val_predict only works for partitions
这对我来说有点令人惊讶,因为根据documentation of sklearn,我们可以在cross_val_predict的cv参数中使用分隔符。我知道我可以使用for循环来完成我想要的事情:
kf = StratifiedShuffleSplit(n_splits=5,test_size=0.2)
X = df.loc[:,"length":"width"]
y = df["weight"]
y_pred = np.zeros(y.size)
for train_idx,test_idx in kf.split(X,df["variety"]):
#get subsets of variables from CV
X_train,X_test = X.iloc[train_idx],X.iloc[test_idx]
y_train,y_test = y.iloc[train_idx],y.iloc[test_idx]
#fit model
lm.fit(X_train,y_train)
pred_vals = lm.predict(X_test)
#store predicted values
y_pred[test_idx] = pred_vals
但是,我希望使用cross_val_predict使代码更紧凑。有可能吗?
解决方法
尝试使用 StratifiedKFold
而不是 StratifiedShuffleSplit
。
不同的是,StratifiedKFold 只混洗和分裂一次,因此测试集不重叠,而 StratifiedShuffleSplit 每次分裂前都会混洗,并且它分裂 n_splits 次,测试集可以重叠并且一些数据分区从不属于测试数据集,这意味着没有对它们的预测。
阅读更多信息