【问题标题】:euclidean distance between two big pandas dataframes两个大熊猫数据框之间的欧几里得距离
【发布时间】:2021-06-22 13:28:20
【问题描述】:

我有三个数据框 df1 有 1 160 164 行和 4 个变量,df2 有 11241 行和 4 个变量,df3 有 1 630 644 行和 6 个变量

df1 看起来像:

df2 看起来像:

df1 中的观察结果是 df3 中energy_kcal_100g_nettoye 已满的观察结果。

df2 中的观察结果是 df3 中的观察结果,energy_kcal_100g_nettoye 不可用。

df3 看起来像:

我需要找到 df1 和 df2 的每一行之间的欧几里得距离(不在 df1 或 df2 内)。然后我需要保留第 5 个最接近的索引来计算 df3 中第 5 个索引上的 energy_kcal_100g_nettoye 的平均值。

我尝试使用此代码,但它永远不会结束:

for index, row in df2.iterrows():
    dist_matrix = df1.apply(lambda row2: [np.linalg.norm(row2.values - row.values)], axis=1)
    dist_matrix=dist_matrix.sort_values()
    observation=dist_matrix[0:5].index
    echantillon=df3.loc[observation]
    df3.loc[index,'energy_kcal_100g_mean_distance_5']=echantillon['energy_kcal_100g_nettoye'].mean()

我想使用矢量化来更快地做到这一点,但我没有成功。我的数据太大了。

你能帮我高兴吗

谢谢

Ps:对不起我的英语

【问题讨论】:

  • 您是否要创建大小为len(df1) x len(df2) 的矩阵?
  • 是的,但我不能。我有记忆错误。我能做些什么 ?如果可能的话;)
  • 一般答案是,您正在尝试分配470. GiB 的数据。您可以尝试将它们保存在磁盘上,但预计会保留那么多空间。

标签: python pandas dataframe numpy euclidean-distance


【解决方案1】:

您应该使用广播通过vertorization来计算它。 This post 实际上给出了答案,但是,如果您只想找到最接近的样本,则不需要计算平方根(最小化平方距离相当于最小化距离)。

为了这个例子,形状为(1000, 4)df1和形状为(200, 4)df2

>>> diff = df1.values - df2.values[:, None, :]
>>> diff.shape
(200, 1000, 4)
>>> dist_squared = np.square(diff).sum(axis=2)
>>> dist_squared.shape
(200, 1000)

您现在拥有一个 200x1000 的每个数据帧的行之间的平方距离矩阵。但这还不清楚你现在想做什么。您可以识别 5 个最接近的 行,但这可能会为您提供 2 x 5 = 10 个不同的行(df1 中的行和df2 中的行)。你可以计算:

>>> closest = dist_squared.argpartition(kth=5, axis=None)[:5]
>>> ids_df1, ids_df2 = np.divmod(closest, 4)

其中ids_df1 包含df1 中最接近df2 中任何行的5 行的索引。但是这些索引不一定是唯一的,这取决于您所说的“我想保留 5 个最接近的索引”的意思。

--- 编辑

确实,此解决方案不适用于您的矩阵大小(您会遇到内存错误)。在不使用分布式框架的情况下,按照您的建议使用 for 循环可能是最简单的事情。但是,您仍然不应该使用np.sqrt 并使用np.argpartition 而不是完全排序,这将加快计算速度。

【讨论】:

  • 这个解决方案出现内存错误。 MemoryError: Unable to allocate 470. GiB for an array with shape (11052, 1142159, 4) and data type float64
【解决方案2】:

我想为 df2 的每一行找到 df1 中最接近的五个行,以计算使用 df3 对这些观察结果的 energy_kcal 的平均值。我这样做是为了估算。当我尝试创建矩阵 len(df1) * len(df2) 时出现内存错误消息。所以我尝试在 df2 上循环以获得 len(df2) 距离矩阵,但它太长了。这个新代码需要 45 分钟:

for index, row in df2.iterrows():
    dist = np.sqrt(np.square(df1 - row).sum(axis=1))
    dist=dist.sort_values()
    df3.loc[index, 'energy_kcal_100g_mean_distance_5']=df3.loc[dist[0:5].index,'energy_kcal_100g_nettoye'].mean()

有没有可能做得更快?

【讨论】:

    猜你喜欢
    • 2019-09-30
    • 2021-01-16
    • 2018-05-26
    • 2021-01-13
    • 2020-09-15
    • 2019-06-19
    • 2018-12-23
    • 2017-09-15
    相关资源
    最近更新 更多