KNN K-最近邻:train_test_split 和 knn.kneighbors
KNN K-Nearest Neighbors : train_test_split and knn.kneighbors
我向那些有使用库 sklearn 中的函数 train_test_split 和 [=42= 的经验的人(我没有)提出以下一般性问题]KNN(K 最近邻) 算法,特别是 knn.kneighbors 函数。
假设您在非常标准的 pandas dataframe(无索引)中有样本,这些列由这些列组成:
- 人名
- 特征 X1
- 特征 X2
- 特征 X3
- 目标 Y1
假设您有 100 行通用数据。
当您调用函数 train_test_split 时,您将具有特征的列作为参数传递(如 df[['X1','X2','X3']]) 和带有目标的列(如 df['Y1']),在 return 中你得到 4 个变量 X_test, X_train, y_test、y_train 随机拆分。
好的。到目前为止一切顺利。
假设在那之后,您使用一种算法 KNN 对测试数据进行预测。
所以你发出如下命令:
knn=KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train,y_train)
y_pred=knn.predict(X_test)
好的。美好的。 y_pred 包含预测。
现在,问题来了,您想看看谁是 X_train 数据点的“邻居”,这些数据点使预测成为可能。
为此,有一个名为 Knn.Kneighbors 的函数 return k 的距离和坐标数组(如 X1 X2 X3 数组)被认为是 X_train 集合中每个数据点的“邻居”的点。
neighbors=knn.kneighbors(X=X_test)
问题是:如何link将neighbors变量中return坐标表示的数据作为特征数组,用原始数据集理解给谁(=>列'Name of person') 这些坐标属于?
我的意思是:对于原始数据集的每一行,都有一个 'Name of a person' 关联。您不会将其传递给 X_train 或 X_test。那么我可以重新link由knn.kneighbors函数return编辑的邻居数组(现在随机混合并且不参考原始数据)到原始数据集吗?
有没有简单的方法重新link回来?我想知道最后 X_train 数据中点的邻居的名称是什么,而不仅仅是函数 knn.kneighbors returns 的匿名坐标数组。
否则我不得不在原始数据集中循环获取邻居坐标以了解他们属于谁...但我希望不要这样做。
在此先感谢大家。
安德里亚
如果您设置 return_distance=False
,函数 knn.kneighbors(X=X_test)
的输出将更具可读性。在这种情况下,结果数组中的每一行代表 X_test
.
中每个点(行)的 n_neighbors
个最近邻居的索引
请注意,这些索引对应于训练集中的索引 X_train
。如果你想将它们映射回原始数据框中的 Name
列,我认为你必须使用 pandas 索引。
我希望下面的例子有意义。
正在创建数据集:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
np.random.seed(42) # for repoducibility
df = pd.DataFrame(np.random.randn(20, 3),
columns=["X1", "X2", "X3"])
df["Name"] = df.index.values * 100 # assume the names are just pandas index * 100
Y = np.random.randint(0, 2, 20) # targets
print(df)
X1 X2 X3 Name
0 0.496714 -0.138264 0.647689 0
1 1.523030 -0.234153 -0.234137 100
2 1.579213 0.767435 -0.469474 200
3 0.542560 -0.463418 -0.465730 300
4 0.241962 -1.913280 -1.724918 400
5 -0.562288 -1.012831 0.314247 500
6 -0.908024 -1.412304 1.465649 600
7 -0.225776 0.067528 -1.424748 700
8 -0.544383 0.110923 -1.150994 800
9 0.375698 -0.600639 -0.291694 900
10 -0.601707 1.852278 -0.013497 1000
11 -1.057711 0.822545 -1.220844 1100
12 0.208864 -1.959670 -1.328186 1200
13 0.196861 0.738467 0.171368 1300
14 -0.115648 -0.301104 -1.478522 1400
15 -0.719844 -0.460639 1.057122 1500
16 0.343618 -1.763040 0.324084 1600
17 -0.385082 -0.676922 0.611676 1700
18 1.031000 0.931280 -0.839218 1800
19 -0.309212 0.331263 0.975545 1900
进行火车测试拆分:
X_train, X_test, y_train, y_test = train_test_split(df.iloc[:, :3],
Y,
random_state=24 # for reproducibility
)
注意每个数据框的索引:
print(X_train)
X1 X2 X3
8 0.375698 -0.600639 -0.291694
14 -0.115648 -0.301104 -1.478522
16 0.343618 -1.763040 0.324084
7 -0.225776 0.067528 -1.424748
10 -0.601707 1.852278 -0.013497
12 0.208864 -1.959670 -1.328186
19 -0.309212 0.331263 0.975545
18 1.031000 0.931280 -0.839218
15 -0.719844 -0.460639 1.057122
11 -1.057711 0.822545 -1.220844
4 0.241962 -1.913280 -1.724918
1 1.523030 -0.234153 -0.234137
0 0.496714 -0.138264 0.647689
3 0.542560 -0.463418 -0.465730
2 1.579213 0.767435 -0.469474
print(X_test)
X1 X2 X3
13 0.196861 0.738467 0.171368
6 -0.908024 -1.412304 1.465649
17 -0.385082 -0.676922 0.611676
5 -0.562288 -1.012831 0.314247
9 0.375698 -0.600639 -0.291694
由于我们已经通过设置随机种子确保了可重复性,让我们进行更改以帮助我们理解 knn.kneighbors(X=X_test)
的结果。我将 X_train
中的第一行设置为与 X_test
的最后一行相同。由于这两点相同,当我们查询 X_test.loc[[9]]
(或 X_test.iloc[4, :]
)时,它应该 return 本身作为最近点。
注意索引为 8 的第一行已更改,等于 X_test
的最后一行:
X_train.loc[8] = X_test.loc[9]
print(X_train)
X1 X2 X3
8 0.375698 -0.600639 -0.291694
14 -0.115648 -0.301104 -1.478522
16 0.343618 -1.763040 0.324084
7 -0.225776 0.067528 -1.424748
10 -0.601707 1.852278 -0.013497
12 0.208864 -1.959670 -1.328186
19 -0.309212 0.331263 0.975545
18 1.031000 0.931280 -0.839218
15 -0.719844 -0.460639 1.057122
11 -1.057711 0.822545 -1.220844
4 0.241962 -1.913280 -1.724918
1 1.523030 -0.234153 -0.234137
0 0.496714 -0.138264 0.647689
3 0.542560 -0.463418 -0.465730
2 1.579213 0.767435 -0.469474
训练 KNN 模型:
knn = KNeighborsClassifier(n_neighbors=2)
knn.fit(X_train, y_train)
为简单起见,让我们获取一个点的最近邻居(同样的解释适用于多个点)。
获取特定点X_test.loc[[9]] = [ 0.375698 -0.600639 -0.291694]
的两个最近邻,我们在上面用它来改变X_train
):
nn_indices = knn.kneighbors(X=X_test.loc[[9]], return_distance=False)
print(nn_indices)
[[ 0 13]]
它们是:
print(X_train.iloc[np.squeeze(nn_indices)])
X1 X2 X3
8 0.375698 -0.600639 -0.291694 < - Same point in X_train
3 0.542560 -0.463418 -0.465730 < - Second closest point in X_train
这意味着X_train
中的行0
和13
最接近点[ 0.375698 -0.600639 -0.291694]
为了将它们映射到名称,您可以使用:
print(df["Name"][np.squeeze(X_train.index.values[nn_indices])])
8 800
3 300
Name: Name, dtype: int64
如果你没有设置return_distance=False
,你会注意到第一个距离值是零(到一个点的距离恰好是它本身是零)
nn_distances, nn_indices = knn.kneighbors(X=X_test.loc[[9]])
print(nn_distances)
[[0. 0.27741858]]
您还可以使用 n_neighbors
参数来获取更多最近的邻居。 By default it will run for value used while fitting the model.
编辑:
对于整个 X_test
,您可以这样做:
nn_indices = knn.kneighbors(X=X_test, return_distance=False)
pd.DataFrame(nn_indices).applymap(lambda x: df["Name"][X_train.index.values[x]])
0 1
0 1900 0
1 1500 1600
2 1500 0
3 1500 1600
4 800 300
我向那些有使用库 sklearn 中的函数 train_test_split 和 [=42= 的经验的人(我没有)提出以下一般性问题]KNN(K 最近邻) 算法,特别是 knn.kneighbors 函数。
假设您在非常标准的 pandas dataframe(无索引)中有样本,这些列由这些列组成:
- 人名
- 特征 X1
- 特征 X2
- 特征 X3
- 目标 Y1
假设您有 100 行通用数据。
当您调用函数 train_test_split 时,您将具有特征的列作为参数传递(如 df[['X1','X2','X3']]) 和带有目标的列(如 df['Y1']),在 return 中你得到 4 个变量 X_test, X_train, y_test、y_train 随机拆分。
好的。到目前为止一切顺利。
假设在那之后,您使用一种算法 KNN 对测试数据进行预测。 所以你发出如下命令:
knn=KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train,y_train)
y_pred=knn.predict(X_test)
好的。美好的。 y_pred 包含预测。
现在,问题来了,您想看看谁是 X_train 数据点的“邻居”,这些数据点使预测成为可能。
为此,有一个名为 Knn.Kneighbors 的函数 return k 的距离和坐标数组(如 X1 X2 X3 数组)被认为是 X_train 集合中每个数据点的“邻居”的点。
neighbors=knn.kneighbors(X=X_test)
问题是:如何link将neighbors变量中return坐标表示的数据作为特征数组,用原始数据集理解给谁(=>列'Name of person') 这些坐标属于?
我的意思是:对于原始数据集的每一行,都有一个 'Name of a person' 关联。您不会将其传递给 X_train 或 X_test。那么我可以重新link由knn.kneighbors函数return编辑的邻居数组(现在随机混合并且不参考原始数据)到原始数据集吗?
有没有简单的方法重新link回来?我想知道最后 X_train 数据中点的邻居的名称是什么,而不仅仅是函数 knn.kneighbors returns 的匿名坐标数组。
否则我不得不在原始数据集中循环获取邻居坐标以了解他们属于谁...但我希望不要这样做。
在此先感谢大家。 安德里亚
如果您设置 return_distance=False
,函数 knn.kneighbors(X=X_test)
的输出将更具可读性。在这种情况下,结果数组中的每一行代表 X_test
.
n_neighbors
个最近邻居的索引
请注意,这些索引对应于训练集中的索引 X_train
。如果你想将它们映射回原始数据框中的 Name
列,我认为你必须使用 pandas 索引。
我希望下面的例子有意义。
正在创建数据集:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
np.random.seed(42) # for repoducibility
df = pd.DataFrame(np.random.randn(20, 3),
columns=["X1", "X2", "X3"])
df["Name"] = df.index.values * 100 # assume the names are just pandas index * 100
Y = np.random.randint(0, 2, 20) # targets
print(df)
X1 X2 X3 Name
0 0.496714 -0.138264 0.647689 0
1 1.523030 -0.234153 -0.234137 100
2 1.579213 0.767435 -0.469474 200
3 0.542560 -0.463418 -0.465730 300
4 0.241962 -1.913280 -1.724918 400
5 -0.562288 -1.012831 0.314247 500
6 -0.908024 -1.412304 1.465649 600
7 -0.225776 0.067528 -1.424748 700
8 -0.544383 0.110923 -1.150994 800
9 0.375698 -0.600639 -0.291694 900
10 -0.601707 1.852278 -0.013497 1000
11 -1.057711 0.822545 -1.220844 1100
12 0.208864 -1.959670 -1.328186 1200
13 0.196861 0.738467 0.171368 1300
14 -0.115648 -0.301104 -1.478522 1400
15 -0.719844 -0.460639 1.057122 1500
16 0.343618 -1.763040 0.324084 1600
17 -0.385082 -0.676922 0.611676 1700
18 1.031000 0.931280 -0.839218 1800
19 -0.309212 0.331263 0.975545 1900
进行火车测试拆分:
X_train, X_test, y_train, y_test = train_test_split(df.iloc[:, :3],
Y,
random_state=24 # for reproducibility
)
注意每个数据框的索引:
print(X_train)
X1 X2 X3
8 0.375698 -0.600639 -0.291694
14 -0.115648 -0.301104 -1.478522
16 0.343618 -1.763040 0.324084
7 -0.225776 0.067528 -1.424748
10 -0.601707 1.852278 -0.013497
12 0.208864 -1.959670 -1.328186
19 -0.309212 0.331263 0.975545
18 1.031000 0.931280 -0.839218
15 -0.719844 -0.460639 1.057122
11 -1.057711 0.822545 -1.220844
4 0.241962 -1.913280 -1.724918
1 1.523030 -0.234153 -0.234137
0 0.496714 -0.138264 0.647689
3 0.542560 -0.463418 -0.465730
2 1.579213 0.767435 -0.469474
print(X_test)
X1 X2 X3
13 0.196861 0.738467 0.171368
6 -0.908024 -1.412304 1.465649
17 -0.385082 -0.676922 0.611676
5 -0.562288 -1.012831 0.314247
9 0.375698 -0.600639 -0.291694
由于我们已经通过设置随机种子确保了可重复性,让我们进行更改以帮助我们理解 knn.kneighbors(X=X_test)
的结果。我将 X_train
中的第一行设置为与 X_test
的最后一行相同。由于这两点相同,当我们查询 X_test.loc[[9]]
(或 X_test.iloc[4, :]
)时,它应该 return 本身作为最近点。
注意索引为 8 的第一行已更改,等于 X_test
的最后一行:
X_train.loc[8] = X_test.loc[9]
print(X_train)
X1 X2 X3
8 0.375698 -0.600639 -0.291694
14 -0.115648 -0.301104 -1.478522
16 0.343618 -1.763040 0.324084
7 -0.225776 0.067528 -1.424748
10 -0.601707 1.852278 -0.013497
12 0.208864 -1.959670 -1.328186
19 -0.309212 0.331263 0.975545
18 1.031000 0.931280 -0.839218
15 -0.719844 -0.460639 1.057122
11 -1.057711 0.822545 -1.220844
4 0.241962 -1.913280 -1.724918
1 1.523030 -0.234153 -0.234137
0 0.496714 -0.138264 0.647689
3 0.542560 -0.463418 -0.465730
2 1.579213 0.767435 -0.469474
训练 KNN 模型:
knn = KNeighborsClassifier(n_neighbors=2)
knn.fit(X_train, y_train)
为简单起见,让我们获取一个点的最近邻居(同样的解释适用于多个点)。
获取特定点X_test.loc[[9]] = [ 0.375698 -0.600639 -0.291694]
的两个最近邻,我们在上面用它来改变X_train
):
nn_indices = knn.kneighbors(X=X_test.loc[[9]], return_distance=False)
print(nn_indices)
[[ 0 13]]
它们是:
print(X_train.iloc[np.squeeze(nn_indices)])
X1 X2 X3
8 0.375698 -0.600639 -0.291694 < - Same point in X_train
3 0.542560 -0.463418 -0.465730 < - Second closest point in X_train
这意味着X_train
中的行0
和13
最接近点[ 0.375698 -0.600639 -0.291694]
为了将它们映射到名称,您可以使用:
print(df["Name"][np.squeeze(X_train.index.values[nn_indices])])
8 800
3 300
Name: Name, dtype: int64
如果你没有设置return_distance=False
,你会注意到第一个距离值是零(到一个点的距离恰好是它本身是零)
nn_distances, nn_indices = knn.kneighbors(X=X_test.loc[[9]])
print(nn_distances)
[[0. 0.27741858]]
您还可以使用 n_neighbors
参数来获取更多最近的邻居。 By default it will run for value used while fitting the model.
编辑:
对于整个 X_test
,您可以这样做:
nn_indices = knn.kneighbors(X=X_test, return_distance=False)
pd.DataFrame(nn_indices).applymap(lambda x: df["Name"][X_train.index.values[x]])
0 1
0 1900 0
1 1500 1600
2 1500 0
3 1500 1600
4 800 300