Machine learning 具有分类值的KNN不能正确预测

Machine learning 具有分类值的KNN不能正确预测,machine-learning,scikit-learn,random-forest,knn,Machine Learning,Scikit Learn,Random Forest,Knn,我试图建立一个模型,给定一个项目,预测它属于哪个商店 我有一个大约250条记录的数据集,这些记录应该是不同网上商店的商品 每个记录由以下部分组成: 类别、子类别、价格、门店标识符(y变量) 我试过几个邻居,试过曼哈顿距离,但不幸的是不能得到更好的结果精度~0.55。 随机森林产生的精度约为0.7 我的直觉是,模型应该能够预测这个问题。我错过了什么 以下是数据: KNN可能会产生具有分类预测因子的良好预测。我以前在这方面很成功。但是有一些东西没有注意到: 数值变量必须在相同的刻度上,例如通过使

我试图建立一个模型,给定一个项目,预测它属于哪个商店

我有一个大约250条记录的数据集,这些记录应该是不同网上商店的商品

每个记录由以下部分组成:
类别、子类别、价格、门店标识符(y变量)

我试过几个邻居,试过曼哈顿距离,但不幸的是不能得到更好的结果精度~0.55。 随机森林产生的精度约为0.7

我的直觉是,模型应该能够预测这个问题。我错过了什么

以下是数据:

KNN可能会产生具有分类预测因子的良好预测。我以前在这方面很成功。但是有一些东西没有注意到:

  • 数值变量必须在相同的刻度上,例如通过使用
  • 可以尝试特定设计的错误度量,例如
除此之外,在一个热编码中实际上还有一个bug:

调用第一个one hot encoder后,您有一个形状数组(273,21):

然后调用第二列上的一个热编码,该列只有两个值(0和1),因此产生:

onehotencoder_1 = OneHotEncoder(categorical_features = [1])
X = onehotencoder_1.fit_transform(X).toarray()
print(X.shape)
print(X[:5,:])

Out:
(275, 22)
[[ 1.    0.    0.    0.    0.    0.    0.    0.    0.    1.    0.    0.
   0.    0.    0.    0.    0.    0.    0.    0.   52.   33.99]
 [ 1.    0.    0.    0.    0.    0.    0.    0.    0.    1.    0.    0.
   0.    0.    0.    0.    0.    0.    0.    0.   52.   33.97]
 [ 1.    0.    0.    0.    0.    0.    0.    0.    0.    1.    0.    0.
   0.    0.    0.    0.    0.    0.    0.    0.   36.   27.97]
 [ 1.    0.    0.    0.    0.    0.    0.    0.    0.    1.    0.    0.
   0.    0.    0.    0.    0.    0.    0.    0.   37.   13.97]
 [ 1.    0.    0.    0.    0.    0.    0.    0.    0.    1.    0.    0.
   0.    0.    0.    0.    0.    0.    0.    0.   20.    9.97]]
因此,如果您可以解决这一问题,或者仅使用实例管道来避免这一问题,并添加数字变量的缩放比例,如下所示:

from sklearn.pipeline import Pipeline, FeatureUnion, make_pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.neighbors import KNeighborsClassifier

class Columns(BaseEstimator, TransformerMixin):
    def __init__(self, names=None):
        self.names = names

    def fit(self, X, y=None, **fit_params):
        return self

    def transform(self, X):
        return X.loc[:,self.names]

dataset = pd.read_csv('data.csv', header=None)
dataset.columns = ["cat1", "cat2", "num1", "target"]

X = dataset.iloc[:, :-1]
y = dataset.iloc[:, 3]

labelencoder_X_0 = LabelEncoder()
X.iloc[:, 0] = labelencoder_X_0.fit_transform(X.iloc[:, 0])

labelencoder_X_1 = LabelEncoder()
X.iloc[:, 1] = labelencoder_X_1.fit_transform(X.iloc[:, 1])

numeric = ["num1"]
categorical = ["cat1", "cat2"]

pipe = Pipeline([
    ("features", FeatureUnion([
        ('numeric', make_pipeline(Columns(names=numeric),StandardScaler())),
        ('categorical', make_pipeline(Columns(names=categorical), OneHotEncoder(sparse=False)))
    ])),
])

X = pipe.fit_transform(X)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, random_state = 0)
# classifier = RandomForestClassifier(n_estimators=25, criterion='entropy', random_state = 0)
classifier = KNeighborsClassifier(n_neighbors=3, metric='minkowski', p=2)
classifier.fit(X_train, y_train)

y_pred = classifier.predict(X_test)
cm = confusion_matrix(y_test, y_pred)

accuracy = classifier.score(X_test, y_test) 
print(accuracy)

Out: 
0.7101449275362319
正如你所见,这至少为随机福勒斯特的球场带来了准确性


所以你接下来可以试试高尔距离。目前正在讨论将其添加到sklearn中,因此您可以查看Ipython笔记本中发布的代码并尝试一下。

非常感谢您的回答!这确实是一个很好的变化。不过我还有一个问题。。一旦我添加了比我之前发布的更多的数据:它似乎将结果推回到了以前的水平。这是为什么呢?嗯,所以我很快用随机福勒斯特进行了检查,它的准确度现在也随着新数据的出现而下降了,而且两者现在仍然在同一个球场上。所以我认为这不再是一个编程问题(因此与这个线程无关)。因此,也许深入挖掘新数据中的不同之处,例如检查类标签的分布,看看类是否平衡,并考虑方法来在不存在类的情况下对此进行跟踪。然后想想你的指标。准确度适合你的问题吗?现在有很多事情要做:)我假设“驻留在数据集中的记录”指的是火车组?嗯,在火车组上,你目前有76%(顺便说一句,这表示装配过度,测试组有62%)。因此,即使是火车组,也有24%的错误!这是意料之中的。对于KNN,这是由于平均了列车组中最相似的k个实例。如前所述,这不是一个编程问题,而是迭代建模和深入挖掘问题。(+1)和我的编辑,因为我删除了自己的答案(不知何故,我完全错过了一个热编码…),要改进您的模型,可能需要做很多事情(添加功能、添加数据、改进建模参数、尝试不同的模型,…),因此,如果要获得更高的精度很重要的话,请继续阅读没完没了的博客和教程。然而,最终可能是,这并不是真的“足够”可预测的(无论在您的情况下意味着什么)但是我认为这是一个话题,太宽泛了,除非你认为你发现了另一个编程错误,然后再考虑另一个问题。祝你好运!
onehotencoder_1 = OneHotEncoder(categorical_features = [1])
X = onehotencoder_1.fit_transform(X).toarray()
print(X.shape)
print(X[:5,:])

Out:
(275, 22)
[[ 1.    0.    0.    0.    0.    0.    0.    0.    0.    1.    0.    0.
   0.    0.    0.    0.    0.    0.    0.    0.   52.   33.99]
 [ 1.    0.    0.    0.    0.    0.    0.    0.    0.    1.    0.    0.
   0.    0.    0.    0.    0.    0.    0.    0.   52.   33.97]
 [ 1.    0.    0.    0.    0.    0.    0.    0.    0.    1.    0.    0.
   0.    0.    0.    0.    0.    0.    0.    0.   36.   27.97]
 [ 1.    0.    0.    0.    0.    0.    0.    0.    0.    1.    0.    0.
   0.    0.    0.    0.    0.    0.    0.    0.   37.   13.97]
 [ 1.    0.    0.    0.    0.    0.    0.    0.    0.    1.    0.    0.
   0.    0.    0.    0.    0.    0.    0.    0.   20.    9.97]]
from sklearn.pipeline import Pipeline, FeatureUnion, make_pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.neighbors import KNeighborsClassifier

class Columns(BaseEstimator, TransformerMixin):
    def __init__(self, names=None):
        self.names = names

    def fit(self, X, y=None, **fit_params):
        return self

    def transform(self, X):
        return X.loc[:,self.names]

dataset = pd.read_csv('data.csv', header=None)
dataset.columns = ["cat1", "cat2", "num1", "target"]

X = dataset.iloc[:, :-1]
y = dataset.iloc[:, 3]

labelencoder_X_0 = LabelEncoder()
X.iloc[:, 0] = labelencoder_X_0.fit_transform(X.iloc[:, 0])

labelencoder_X_1 = LabelEncoder()
X.iloc[:, 1] = labelencoder_X_1.fit_transform(X.iloc[:, 1])

numeric = ["num1"]
categorical = ["cat1", "cat2"]

pipe = Pipeline([
    ("features", FeatureUnion([
        ('numeric', make_pipeline(Columns(names=numeric),StandardScaler())),
        ('categorical', make_pipeline(Columns(names=categorical), OneHotEncoder(sparse=False)))
    ])),
])

X = pipe.fit_transform(X)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, random_state = 0)
# classifier = RandomForestClassifier(n_estimators=25, criterion='entropy', random_state = 0)
classifier = KNeighborsClassifier(n_neighbors=3, metric='minkowski', p=2)
classifier.fit(X_train, y_train)

y_pred = classifier.predict(X_test)
cm = confusion_matrix(y_test, y_pred)

accuracy = classifier.score(X_test, y_test) 
print(accuracy)

Out: 
0.7101449275362319