我是机器学习的新手,并且想使用带有Python库k-nearest-Neighbor-methodScikit设置一些示例。

转换和拟合数据可以很好地工作,但是我无法弄清楚如何绘制一个显示数据点被其“邻居”包围的图形。

我正在使用的dataset看起来像这样:

python - 绘制具有8个特征的k最近邻图?-LMLPHP
因此,这里有8个功能,外加一个“结果”列。

根据我的理解,我得到了一个数组,使用euclidean-distances中的 kneighbors_graph 显示了所有数据点的Scikit
因此,我的第一个尝试是“简单地”绘制从该方法获得的矩阵。像这样:

def kneighbors_graph(self):
    self.X_train = self.X_train.values[:10,] #trimming down the data to only 10 entries
    A = neighbors.kneighbors_graph(self.X_train, 9, 'distance')
    plt.spy(A)
    plt.show()

但是,结果图并不能真正可视化数据点之间的预期关系。
python - 绘制具有8个特征的k最近邻图?-LMLPHP

因此,我试图调整您可以在每个页面上找到的有关Scikit,Iris_dataset的示例。不幸的是,它仅使用两个功能,因此它并不是我想要的,但我仍然希望至少获得第一个输出:
  def plot_classification(self):
    h = .02
    n_neighbors = 9
    self.X = self.X.values[:10, [1,4]] #trim values to 10 entries and only columns 2 and 5 (indices 1, 4)
    self.y = self.y[:10, ] #trim outcome column, too

    clf = neighbors.KNeighborsClassifier(n_neighbors, weights='distance')
    clf.fit(self.X, self.y)

    x_min, x_max = self.X[:, 0].min() - 1, self.X[:, 0].max() + 1
    y_min, y_max = self.X[:, 1].min() - 1, self.X[:, 1].max() + 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]) #no errors here, but it's  not moving on until computer crashes

    cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA','#00AAFF'])
    cmap_bold = ListedColormap(['#FF0000', '#00FF00','#00AAFF'])
    Z = Z.reshape(xx.shape)
    plt.figure()
    plt.pcolormesh(xx, yy, Z, cmap=cmap_light)
    plt.scatter(self.X[:, 0], self.X[:, 1], c=self.y, cmap=cmap_bold)
    plt.xlim(xx.min(), xx.max())
    plt.ylim(yy.min(), yy.max())
    plt.title("Classification (k = %i)" % (n_neighbors))

但是,此代码根本不起作用,我也不知道为什么。它永远不会终止,所以我没有遇到任何我可以使用的错误。等待几分钟后,我的电脑便崩溃了。

代码苦苦挣扎的那一行是 Z = clf.predict(np.c_ [xx.ravel(),yy.ravel()])部分

所以我的问题是:

首先,我不明白为什么我需要 fit 预测来绘制邻居。欧氏距离是否不足以绘制所需的图? (所需的图形看起来有点像:有两种颜色可用于糖尿病或非糖尿病;无需箭头等;照片来源:this tutorial)。

python - 绘制具有8个特征的k最近邻图?-LMLPHP

我的代码错误在哪里/为什么预测崩溃?

有没有一种方法可以使用所有功能来绘制数据?我知道我不能有8个轴,但是我想用所有8个特征而不是只有两个特征来计算欧几里得距离(有两个不是很准确,是吗?)。

更新

这是一个使用虹膜代码的工作示例,但是我的糖尿病数据集:
它使用我的数据集的前两个功能。我对代码的唯一区别是数组的剪切->这里需要前两个功能,我想要功能2和5,所以我以不同的方式剪切它。但是我不明白为什么我的作品行不通。这是工作代码;复制并粘贴它,它与我之前提供的数据集一起运行:
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn import neighbors, datasets

diabetes = pd.read_csv('data/diabetes_data.csv')
columns_to_iterate = ['glucose', 'diastolic', 'triceps', 'insulin', 'bmi', 'dpf', 'age']
for column in columns_to_iterate:
    mean_value = diabetes[column].mean(skipna=True)
    diabetes = diabetes.replace({column: {0: mean_value}})
    diabetes[column] = diabetes[column].astype(np.float64)
X = diabetes.drop(columns=['diabetes'])
y = diabetes['diabetes'].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,
                                                                        random_state=1, stratify=y)
n_neighbors = 6

X = X.values[:, :2]
y = y
h = .02

cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#00AAFF'])
cmap_bold = ListedColormap(['#FF0000', '#00FF00', '#00AAFF'])

clf = neighbors.KNeighborsClassifier(n_neighbors, weights='distance')
clf.fit(X, y)

x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                     np.arange(y_min, y_max, h))

Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])

Z = Z.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx, yy, Z, cmap=cmap_light)

plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("3-Class classification (k = %i)" % (n_neighbors))
plt.show()

python - 绘制具有8个特征的k最近邻图?-LMLPHP

最佳答案

目录:

  • 功能之间的关系
  • 所需图形
  • 为什么适合并预测?
  • 绘制8个功能?

  • 功能之间的关系:

    表征特征之间“关系”的科学术语是correlation。这个区域大部分是在PCA (Principal Component Analysis)期间探索的。这个想法并不是您的所有功能都很重要,或者至少其中一些功能是高度相关的。可以认为这是相似的:如果两个功能高度相关,那么它们体现的信息是相同的,因此您可以删除其中之一。使用pandas看起来像这样:

    import pandas as pd
    import seaborn as sns
    from pylab import rcParams
    import matplotlib.pyplot as plt
    
    
    def plot_correlation(data):
        '''
        plot correlation's matrix to explore dependency between features
        '''
        # init figure size
        rcParams['figure.figsize'] = 15, 20
        fig = plt.figure()
        sns.heatmap(data.corr(), annot=True, fmt=".2f")
        plt.show()
        fig.savefig('corr.png')
    
    # load your data
    data  = pd.read_csv('diabetes.csv')
    
    # plot correlation & densities
    plot_correlation(data)
    

    输出为以下相关矩阵:
    python - 绘制具有8个特征的k最近邻图?-LMLPHP

    因此,这里1表示总相关,并且正如预期的那样,对角线全为1,因为特征与其自身完全相关。同样,数字越小,特征之间的相关性就越低。

    在这里,我们需要考虑特征与特征之间的相关性以及结果与特征之间的相关性。特征之间:更高的相关性意味着我们可以删除其中之一。但是,特征与结果之间的高度相关性意味着该特征很重要,并且拥有很多信息。在我们的图形中,最后一行代表特征与结果之间的相关性。因此,最高值/最重要的特征是“葡萄糖”(0.47)和“MBI”(0.29)。此外,这两者之间的相关性相对较低(0.22),这意味着它们并不相似。

    我们可以使用与结果相关的每个特征的密度图来验证这些结果。这并不是那么复杂,因为我们只有两个结果:0或1。因此在代码中看起来像这样:

    import pandas as pd
    from pylab import rcParams
    import matplotlib.pyplot as plt
    
    
    def plot_densities(data):
        '''
        Plot features densities depending on the outcome values
        '''
        # change fig size to fit all subplots beautifully
        rcParams['figure.figsize'] = 15, 20
    
        # separate data based on outcome values
        outcome_0 = data[data['Outcome'] == 0]
        outcome_1 = data[data['Outcome'] == 1]
    
        # init figure
        fig, axs = plt.subplots(8, 1)
        fig.suptitle('Features densities for different outcomes 0/1')
        plt.subplots_adjust(left = 0.25, right = 0.9, bottom = 0.1, top = 0.95,
                            wspace = 0.2, hspace = 0.9)
    
        # plot densities for outcomes
        for column_name in names[:-1]:
            ax = axs[names.index(column_name)]
            #plt.subplot(4, 2, names.index(column_name) + 1)
            outcome_0[column_name].plot(kind='density', ax=ax, subplots=True,
                                        sharex=False, color="red", legend=True,
                                        label=column_name + ' for Outcome = 0')
            outcome_1[column_name].plot(kind='density', ax=ax, subplots=True,
                                         sharex=False, color="green", legend=True,
                                         label=column_name + ' for Outcome = 1')
            ax.set_xlabel(column_name + ' values')
            ax.set_title(column_name + ' density')
            ax.grid('on')
        plt.show()
        fig.savefig('densities.png')
    
    # load your data
    data  = pd.read_csv('diabetes.csv')
    names = list(data.columns)
    
    # plot correlation & densities
    plot_densities(data)
    

    输出为以下密度图:
    python - 绘制具有8个特征的k最近邻图?-LMLPHP

    在图中,当绿色曲线和红色曲线几乎相同(重叠)时,这表示特征未将结果分开。在“BMI”的情况下,您会看到一些分隔(两条曲线之间的轻微水平偏移),而在“葡萄糖”中,这更加清晰(这与相关值一致)。

    =>这样的结论:如果我们只需要选择2个功能,则可以选择“葡萄糖”和“MBI”。

    所需图形

    关于该图,除了该图代表了k最近邻概念的基本解释之外,我没有太多要说的了。它只是而不是表示的分类。

    为什么适合并预测

    好吧,这是一个基本且至关重要的机器学习(ML)概念。您有一个数据集= [inputs,associated_outputs],并且您想构建一个ML算法,可以很好地学习将输入与其associated_outputs相关联。这是一个两步过程。首先,您要训练/教算法如何完成。在此阶段,您只需像对待 child 一样将输入和答案提供给它。第二步是测试;现在 child 已经学会了,您想测试他/他。因此,您可以给她/他类似的输入,并检查她/他的答案是否正确。现在,您不想给他/他相同的输入,因为即使他/他给出了正确的答案,她/他也可能只是记住了学习阶段的答案(这被称为overfitting),所以她/他没有学到东西。

    同样,您对算法进行处理,首先将数据集分为训练数据和测试数据。然后,在这种情况下,您可以将训练数据拟合到算法或分类器中。这称为训练阶段。之后,您将测试分类器的性能,以及分类器是否可以正确分类新数据。那是测试阶段。根据测试结果,您可以使用不同的evaluation-metrics(例如准确性)来评估分类的性能。经验法则是将2/3的数据用于训练,将1/3的数据用于测试。

    绘制8个功能?

    简单的答案是您无法做到的,如果可以的话,请告诉我如何做。

    有趣的答案:可以可视化8个维度,这很容易...只需想象n维,然后让n = 8或仅可视化3-D并尖叫8个即可。

    逻辑答案:因此,我们生活在物理单词中,看到的对象是3维的,因此从技术上讲是极限。但是,您可以像在here中一样将第4维显示为颜色,也可以将时间用作5维,并使绘图成为动画。 @Rohan在他的答案形状中提出了建议,但是他的代码对我不起作用,而且我不认为这将如何很好地表示算法性能。无论如何,颜色,时间,形状……一段时间后,您会发现自己陷于困境。这是人们进行PCA的原因之一。您可以在dimensionality-reduction下阅读有关此问题方面的信息。

    那么,如果我们在PCA之后获得2个要素,然后进行训练,测试,评估和绘图,会发生什么情况?

    好吧,您可以使用以下代码实现这一目标:

    import warnings
    import numpy as np
    import pandas as pd
    from pylab import rcParams
    import matplotlib.pyplot as plt
    from sklearn import neighbors
    from matplotlib.colors import ListedColormap
    from sklearn.neighbors import KNeighborsClassifier
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import accuracy_score, classification_report
    # filter warnings
    warnings.filterwarnings("ignore")
    
    def accuracy(k, X_train, y_train, X_test, y_test):
        '''
        compute accuracy of the classification based on k values
        '''
        # instantiate learning model and fit data
        knn = KNeighborsClassifier(n_neighbors=k)
        knn.fit(X_train, y_train)
    
        # predict the response
        pred = knn.predict(X_test)
    
        # evaluate and return  accuracy
        return accuracy_score(y_test, pred)
    
    def classify_and_plot(X, y):
        '''
        split data, fit, classify, plot and evaluate results
        '''
        # split data into training and testing set
        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.33, random_state = 41)
    
        # init vars
        n_neighbors = 5
        h           = .02  # step size in the mesh
    
        # Create color maps
        cmap_light = ListedColormap(['#FFAAAA', '#AAAAFF'])
        cmap_bold  = ListedColormap(['#FF0000', '#0000FF'])
    
        rcParams['figure.figsize'] = 5, 5
        for weights in ['uniform', 'distance']:
            # we create an instance of Neighbours Classifier and fit the data.
            clf = neighbors.KNeighborsClassifier(n_neighbors, weights=weights)
            clf.fit(X_train, y_train)
    
            # Plot the decision boundary. For that, we will assign a color to each
            # point in the mesh [x_min, x_max]x[y_min, y_max].
            x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
            y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
            xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                                 np.arange(y_min, y_max, h))
            Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    
            # Put the result into a color plot
            Z = Z.reshape(xx.shape)
            fig = plt.figure()
            plt.pcolormesh(xx, yy, Z, cmap=cmap_light)
    
            # Plot also the training points, x-axis = 'Glucose', y-axis = "BMI"
            plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold, edgecolor='k', s=20)
            plt.xlim(xx.min(), xx.max())
            plt.ylim(yy.min(), yy.max())
            plt.title("0/1 outcome classification (k = %i, weights = '%s')" % (n_neighbors, weights))
            plt.show()
            fig.savefig(weights +'.png')
    
            # evaluate
            y_expected  = y_test
            y_predicted = clf.predict(X_test)
    
            # print results
            print('----------------------------------------------------------------------')
            print('Classification report')
            print('----------------------------------------------------------------------')
            print('\n', classification_report(y_expected, y_predicted))
            print('----------------------------------------------------------------------')
            print('Accuracy = %5s' % round(accuracy(n_neighbors, X_train, y_train, X_test, y_test), 3))
            print('----------------------------------------------------------------------')
    
    
    # load your data
    data  = pd.read_csv('diabetes.csv')
    names = list(data.columns)
    
    # we only take the best two features and prepare them for the KNN classifier
    rows_nbr = 30 # data.shape[0]
    X_prime  = np.array(data.iloc[:rows_nbr, [1,5]])
    X        = X_prime # preprocessing.scale(X_prime)
    y        = np.array(data.iloc[:rows_nbr, 8])
    
    # classify, evaluate and plot results
    classify_and_plot(X, y)
    

    使用权重='均匀'和权重='距离'得出以下决策边界图(以读取两个go here之间的差异):

    python - 绘制具有8个特征的k最近邻图?-LMLPHP
    python - 绘制具有8个特征的k最近邻图?-LMLPHP

    请注意: x轴=“葡萄糖”,y轴=“BMI”

    改进:

    K值
    使用什么k值?有多少邻居要考虑。 k值低意味着数据之间的依赖性较小,而k值越大意味着运行时间更长。因此,这是一个妥协。您可以使用以下代码来找到k值,以得到最高的精度:

    best_n_neighbours = np.argmax(np.array([accuracy(k, X_train, y_train, X_test, y_test) for k in range(1, int(rows_nbr/2))])) + 1
    print('For best accuracy use k = ', best_n_neighbours)
    

    使用更多数据
    因此,当使用所有数据时,您可能会遇到内存问题(如我所做的那样),而不仅仅是过度拟合问题。您可以通过预处理数据来克服这一问题。将其视为数据的缩放和格式设置。在代码中只需使用:

    from sklearn import preprocessing
    X = preprocessing.scale(X_prime)
    

    完整的代码可以在此gist中找到

    关于python - 绘制具有8个特征的k最近邻图?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56153726/

    10-12 17:30
    查看更多