使用 KDTree/KNN Return 最近邻

Use KDTree/KNN Return Closest Neighbors

我有两个 python pandas 数据帧。一个包含自 2007 年以来所有 NFL 四分卫的大学橄榄球统计数据以及他们的球员类型标签(精英、平均、低于平均水平)。另一个数据框包含本赛季所有大学橄榄球 qbs 数据以及预测标签。

我想 运行 进行某种分析,根据每个大学橄榄球 qb 的标签确定两个最接近的 NFL 比较。我想将两个可比较的 qb 作为两个新列添加到第二个数据框。

两个数据框中的特征名称相同。这是数据框的样子:

Player     Year    Team    GP    Comp %   YDS    TD   INT     Label
Player A   2020     ASU    12     65.5    3053   25    6     Average

对于上面的示例,我想要两个从第一个数据帧中找到距离玩家 A 最近的两个邻居,它们也具有标签 "Average"。 我想到的方法是使用 Scipy 的 KDTree 和 运行 查询树:

tree = KDTree(nfl[features], leafsize=nfl[features].shape[0]+1)
closest = []

for row in college.iterrows():
    distances, ndx = tree.query(row[features], k=2)
    closest.append(ndx)
print(closest)

但是,打印语句返回了一个空列表。这是解决我问题的正确方法吗?

.iterrows(), will return namedtuples (index, Series) 其中 index 显然是行的索引,而 Series 是特征值,其中索引是列名(参见以下)。

正如您所拥有的那样,row 被存储为该元组,因此当您拥有 row[features] 时,它实际上不会做任何事情。您真正追求的是具有 row[1] 特征和价值的系列。因此,您可以直接调用它,也可以通过 for idx, row in df.iterrows(): 在循环中将它们分解。然后你就可以调用那个系列 row.

Scikit learn 是一个很好用的包(实际上是建立在 Scipy 上的,所以你会注意到相同的语法)。你必须根据你的规范编辑代码(比如过滤器只有 "Average" 玩家,也许你正在对类别列进行单热编码,在这种情况下可能需要将其添加到功能等。 ),但为了给你一个想法(我编造这些数据框只是为了举个例子……实际上 nfl 是准确的,但大学完全编造了),你可以在下面看到使用 kdtree 然后将每一行放入college 数据框,以查看它最接近 nfl 数据框中的哪 2 个值。我显然让它打印出了名字,但是正如你在 print(closest) 中看到的那样,原始数组就在那里。

import pandas as pd

nfl = pd.DataFrame([['Tom Brady','1999','Michigan',11,61.0,2217,16,6,'Average'],
                   ['Aaron Rodgers','2004','California',12,66.1,2566,24,8,'Average'],
                   ['Payton Manning','1997','Tennessee',12,60.2,3819,36,11,'Average'],
                   ['Drew Brees','2000','Perdue',12,60.4,3668,26,12,'Average'],
                   ['Dan Marino','1982','Pitt',12,58.5,2432,17,23,'Average'],
                   ['Joe Montana','1978','Notre Dame',11,54.2,2010,10,9,'Average']],
                    columns = ['Player','Year','Team','GP','Comp %','YDS','TD','INT','Label'])


college = pd.DataFrame([['Joe Smith','2019','Illinois',11,55.6,1045,15,7,'Average'],
                   ['Mike Thomas','2019','Wisconsin',11,67,2045,19,11,'Average'],
                   ['Steve Johnson','2019','Nebraska',12,57.3,2345,9,19,'Average']],
                    columns = ['Player','Year','Team','GP','Comp %','YDS','TD','INT','Label'])


features = ['GP','Comp %','YDS','TD','INT']

from sklearn.neighbors import KDTree
tree = KDTree(nfl[features], leaf_size=nfl[features].shape[0]+1)
closest = []

for idx, row in college.iterrows():

    X = row[features].values.reshape(1, -1)
    distances, ndx = tree.query(X, k=2, return_distance=True)
    closest.append(ndx)

    collegePlayer = college.loc[idx,'Player']
    closestPlayers = [ nfl.loc[x,'Player'] for x in ndx[0] ]

    print ('%s closest to: %s' %(collegePlayer, closestPlayers))

print(closest)

输出:

Joe Smith closest to: ['Joe Montana', 'Tom Brady']
Mike Thomas closest to: ['Joe Montana', 'Tom Brady']
Steve Johnson closest to: ['Dan Marino', 'Tom Brady']