web-dev-qa-db-ja.com

8つの特徴を持つk最近傍グラフをプロットしますか?

私は機械学習が初めてです。k-nearest-Neighbor-methodPythonライブラリScikitを使用して小さなサンプルをセットアップしたいと思います。

データの変換とフィッティングは正常に機能しますが、「近傍」で囲まれたデータポイントを示すグラフをプロットする方法がわかりません。

dataset 私が使用しているのは次のようなものです:

Head of dataset. したがって、8つの機能と1つの「結果」列があります。

私の理解から、Scikitの-​​kneighbors_graphを使用して、すべてのデータポイントのeuclidean-distancesを示す配列を取得します。したがって、私の最初の試みは、その方法の結果として得られるマトリックスを「単純に」プロットすることでした。そのようです:

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()

ただし、結果グラフは、データポイント間の予想される関係を実際には視覚化しません。 Result graph with kneighbors_graph - method

そこで、Iris_datasetであるScikitに関するすべてのページにあるサンプルを調整してみました。残念ながら、これは2つの機能のみを使用するため、私が探しているものとは異なりますが、少なくとも最初の出力を取得したかったのです。

  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()])の部分です

だから私の質問は:

まず、なぜ隣人をプロットするためにfitpredictが必要なのかがまったくわかりません。ユークリッド距離は、目的のグラフをプロットするのに十分ではありませんか? (望ましいグラフはややこのようになります:糖尿病かそうでないかの2色を持っています;矢印などは必要ありません。写真のクレジット: このチュートリアル )。

desired graph

コードのどこに間違いがありますか?予測部分がクラッシュするのはなぜですか?

all機能を使用してデータをプロットする方法はありますか?私は8つの軸は使用できないことを理解していますが、ユークリッド距離は2つだけではなく8つのすべてのフィーチャで計算されます(2つではあまり正確ではありませんね)。

更新

以下は、虹彩コードの実際の例ですが、私の糖尿病データセットです。これは、私のデータセットの最初の2つの機能を使用しています。私のコードでわかる唯一の違いは、配列の切り取りです->ここでは、最初の2つの機能を使用します。機能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()

Outcome of sample code

10
sonja

目次:

  1. 機能間の関係
  2. 望ましいグラフ
  3. なぜフィットして予測するのですか?
  4. 8つの機能をプロットしますか?

機能間の関係:

機能間の「関係」を特徴付ける科学用語は correlation です。この領域は主に PCA(主成分分析) の間に探索されます。アイデアは、すべての機能が重要であるとは限らず、少なくともそれらのいくつかは高度に相関しているということです。これを類似性と考えてください。2つの機能が非常に相関しているため、同じ情報を具体化しているため、そのうちの1つを削除できます。 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)

出力は次の相関行列です: enter image description here

したがって、ここでは1は完全な相関を意味し、機能は完全に自己と相関しているため、対角線はすべて1です。また、数値が低いほど、特徴の相関は低くなります。

ここでは、機能と機能の相関と結果と機能の相関を考慮する必要があります。機能間:相関が高いほど、それらの1つを削除できます。ただし、機能と結果の相関が高いことは、機能が重要であり、多くの情報を保持していることを意味します。このグラフの最後の線は、特徴と結果の相関を表しています。したがって、最も高い値/最も重要な特徴は「グルコース」(0.47)と「MBI」(0.29)です。さらに、これら2つの間の相関は比較的低く(0.22)、これはそれらが類似していないことを意味します。

これらの結果は、結果に関連する各特徴の密度プロットを使用して確認できます。 2つの結果(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)

出力は次の密度プロットです: enter image description here

プロットでは、緑と赤の曲線がほぼ同じ(重複)の場合、機能が結果を分離しないことを意味します。 「BMI」の場合、いくらかの分離(両方の曲線間のわずかな水平シフト)を確認できます。「グルコース」では、これははるかに明確です(これは相関値と一致しています)。

=>この結論:2つの機能のみを選択する必要がある場合は、「グルコース」と「MBI」を選択します。

必要なグラフ

グラフがk最近傍の概念の基本的な説明を表すことを除いて、私はこれについて多くを言う必要はありません。それは単に分類の表現ではありません

フィットと予測の理由

これは基本的で重要な機械学習(ML)の概念です。データセット= [入力、関連付けられた出力]があり、入力を関連付けられた出力に関連付けることをよく学ぶMLアルゴリズムを構築したいとします。これは2ステップの手順です。最初に、アルゴリズムのトレーニング方法を教えます。この段階では、子供と同じように入力と答えを与えるだけです。 2番目のステップはテストです。子供が学んだので、あなたは彼女/彼をテストしたいと思います。したがって、あなたは彼女/彼に同様の入力を与え、彼女/彼の答えが正しいかどうかを確認します。ここで、彼/彼が学んだ同じ入力を彼女/彼に与えたくないのは、彼女/彼が正しい答えを与えたとしても、彼女/彼はおそらく学習段階からの答えを記憶しただけだからです(これは overfitting)と呼ばれます =)そして彼女/彼は物事を学びませんでした。

同様に、アルゴリズムを使用して、最初にデータセットをトレーニングデータとテストデータに分割します。次に、この場合、トレーニングデータをアルゴリズムまたは分類子に適合させます。これはトレーニングフェーズと呼ばれます。その後、分類子がどの程度優れているか、および新しいデータを正しく分類できるかどうかをテストします。それがテスト段階です。テスト結果に基づいて、たとえば精度のようなさまざまな evaluation-metrics を使用して分類のパフォーマンスを評価します。ここでの経験則では、データの2/3をトレーニングに、1/3をテストに使用します。

8つの機能をプロットしますか?

簡単な答えは不可能ではありません。可能であれば、方法を教えてください。

おもしろい答え:8次元を視覚化するのは簡単です... n次元を想像してn = 8にするか、3Dを視覚化するだけですそしてそれで8を叫ぶ。

論理的な答え:したがって、物理的なWordに住んでおり、表示されるオブジェクトは3次元であるため、技術的には制限の一種です。ただし、4次元を here のように色として視覚化できます。時間を5次元として使用して、プロットをアニメーションにすることもできます。 @Rohanは彼の回答の形で提案しましたが、彼のコードは私にとっては機能しませんでした。これがアルゴリズムのパフォーマンスを適切に表現する方法がわかりません。とにかく、色、時間、形...しばらくしてそれらを使い果たすと、行き詰まってしまいます。これがPCAを行う理由の1つです。この問題の側面については、 dimensionity-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)

これにより、次の判定境界のプロットが、weights = 'uniform'およびweights = 'distance'を使用して作成されます(両方のgoの違いを読み取るため here ):

enter image description hereenter image description here

注意:x軸= 'グルコース'、y軸= 'BMI'

改善:

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

5
SuperKogito

これらの2つの単純なコードを試してください。どちらも6変数の3Dグラフをプロットします。高次元データのプロットは常に困難ですが、それをいじって、目的の近傍グラフを取得するために調整できるかどうかを確認できます。

最初のものはかなり直感的ですが、ランダムな光線またはボックスを与えます(変数の数に依存します)6つを超える変数をプロットすることはできません。他の2つの変数。コードの2番目の部分が表示されると、理にかなっています。

最初のコード

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
X, Y, Z, U, V, W = Zip(*df)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.quiver(X, Y, Z, U, V, W)    
ax.set_xlim([-2, 2])
ax.set_ylim([-2, 2])
ax.set_zlim([-2, 2])
ax.legend()
plt.show()

2番目のコード

ここでは、データポイントの色と形状として年齢とBMIを使用しています。このコードを調整し、他の2つの変数を使用して色または形状で区別することにより、6つの変数の近傍グラフを再び取得できます。

fig = plt.figure(figsize=(8, 6))
t = fig.suptitle('name_of_your_graph', fontsize=14)
ax = fig.add_subplot(111, projection='3d')

xs = list(df['pregnancies'])
ys = list(df['glucose'])
zs = list(df['bloodPressure'])
data_points = [(x, y, z) for x, y, z in Zip(xs, ys, zs)]

ss = list(df['skinThickness'])
colors = ['red' if age_group in range(0,35) else 'yellow' for age_group in list(df['age'])]
markers = [',' if q > 33 else 'x' if q in range(19,32) else 'o' for q in list(df['BMI'])]

for data, color, size, mark in Zip(data_points, colors, ss, markers):
    x, y, z = data
    ax.scatter(x, y, z, alpha=0.4, c=color, edgecolors='none', s=size, marker=mark)

ax.set_xlabel('pregnancies')
ax.set_ylabel('glucose')
ax.set_zlabel('bloodPressure')

あなたの答えを投稿してください。私はいくつかの助けになることができる同様の問題に取り組んでいます。すべての8-Dをプロットできなかった場合は、毎回6つの異なる変数の組み合わせを使用して、複数の近傍グラフをプロットすることもできます。

5
Rohan Kumar