【问题标题】:Reshape the structure of a dataframe重塑数据框的结构
【发布时间】:2020-11-23 11:38:09
【问题描述】:

在包含点(行)和坐标(列)的数据帧 df 中,我想为每个点计算 n 个最近邻点和相应的距离。

我做了这样的事情:

df = pd.DataFrame(np.random.rand(4, 6))

def dist(p, q):  
    return ((p - q)**2).sum(axis=1)

def f(s):
    closest = dist(s, df).nsmallest(3)
    return list(closest.index) + list(closest) 

df.apply(f, axis=1, result_type="expand")

给出:

     0    1    2    3         4         5
0  0.0  3.0  2.0  0.0  0.743722  1.140251
1  1.0  2.0  0.0  0.0  1.548676  1.695104
2  2.0  3.0  0.0  0.0  0.702797  1.140251
3  3.0  2.0  0.0  0.0  0.702797  0.743722

(前3列是最近点的索引,后3列是对应的距离)

但是,我希望获得一个包含 3 列的数据框:点、离它最近的点、它们之间的距离。 换句话说:我希望每距离一列,而不是每点一列

我尝试了 pd.melt、pd.pivot 但没有找到任何好的方法...

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    选项 1:Scikit-learn NearestNeighbors 类

    要找到 k 近邻 (kNN),sklearn.neighbors.NearestNeighbors 就可以达到目的。

    数据

    import numpy as np
    import pandas as pd
    
    np.random.seed(52)  # reproducibility
    df = pd.DataFrame(np.random.rand(4, 6))
    
    print(df)
              0         1         2         3         4         5
    0  0.823110  0.026118  0.210771  0.618422  0.098284  0.620131
    1  0.053890  0.960654  0.980429  0.521128  0.636553  0.764757
    2  0.764955  0.417686  0.768805  0.423202  0.926104  0.681926
    3  0.368456  0.858910  0.380496  0.094954  0.324891  0.415112
    

    代码

    from sklearn.neighbors import NearestNeighbors
    
    k = 3
    dist, indices = NearestNeighbors(n_neighbors=k).fit(df).kneighbors(df)
    

    结果

    print(dist)
    array([[0.00000000e+00, 1.09330867e+00, 1.13862254e+00],
           [0.00000000e+00, 9.32862532e-01, 9.72369661e-01],
           [0.00000000e+00, 9.72369661e-01, 1.02130721e+00],
           [2.10734243e-08, 9.32862532e-01, 1.02130721e+00]])
    
    print(indices)
    array([[0, 2, 3],
           [1, 3, 2],
           [2, 1, 3],
           [3, 1, 2]])
    

    获得的距离和索引可以很容易地重新排列。

    选项 2:手动计算(除了自己最近)

    sklearn.metrics 有一个内置的欧式距离函数,它输出一个形状为[#rows x #rows] 的数组。您可以从min()argmin() 中排除对角线元素(到自身的距离,即0),方法是用无穷大填充。

    代码

    from sklearn.metrics import euclidean_distances
    
    dist = euclidean_distances(df.values, df.values)
    np.fill_diagonal(dist, np.inf)  # exclude self from min()
    
    df_want = pd.DataFrame({
        "point": range(df.shape[0]),
        "closest_point": dist.argmin(axis=1),
        "distance": dist.min(axis=1)    
    })
    

    结果

    print(df_want)
       point  closest_point  distance
    0      0              2  1.093309
    1      1              3  0.932863
    2      2              1  0.972370
    3      3              1  0.932863
    

    【讨论】:

    • 感谢您的回答。但是,我需要获取每个点的 n 个最近邻居,而不仅仅是最近的一个(我不需要存储每个邻居的排名)。每个 id 应该在“point”列中出现 n 次。
    • 我不明白你指的是什么。您可以在帖子中明确说明这一点吗?
    • 我要计算每个点的k个最近邻,我会尽量说清楚。
    • 那么有一个 sklearn.neighbors.NearestNeighbors 类正是为了这个目的。我已经更新了答案中的用法。
    猜你喜欢
    • 1970-01-01
    • 2014-11-15
    • 1970-01-01
    • 2013-01-27
    • 2015-10-07
    • 2019-05-29
    相关资源
    最近更新 更多