Ближайшая запись и соответствующее расстояние между каждой записью в двух кадрах данных - PullRequest
0 голосов
/ 13 февраля 2019

Предположим, у меня есть два DataFrame s: XA и XB, например, каждый с 3 строками и 2 столбцами:

import pandas as pd

XA = pd.DataFrame({
    'x1': [1, 2, 3],
    'x2': [4, 5, 6]
})

XB = pd.DataFrame({
    'x1': [8, 7, 6],
    'x2': [5, 4, 3]
})

Для каждой записи в XA я хочунайдите ближайшую запись (например, основанную на евклидовом расстоянии) в XB, а также соответствующее расстояние.Например, это может вернуть DataFrame с индексом id_A и столбцами для id_B и distance.

Как я могу сделать это наиболее эффективно?

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Модифицируя этот ответ , чтобы избежать матрицы полного расстояния, вы можете найти ближайшую запись и расстояние для каждой строки в XA (nearest_record1()), а затем вызвать apply, чтобы просмотреть ее.каждый ряд (nearest_record()).Это сокращает время выполнения на ~ 85% в тесте .

from scipy.spatial.distance import cdist

def nearest_record1(XA1, XB):
    """Get the nearest record between XA1 and XB.

    Args:
        XA: Series.
        XB: DataFrame.

    Returns:
        DataFrame with columns for id_B (from XB) and dist.
    """
    dist = cdist(XA1.values.reshape(1, -1), XB)[0]
    return pd.Series({'dist': np.amin(dist), 'id_B': np.argmin(dist)})

def nearest_record(XA, XB):
    """Get the nearest record in XA for each record in XB.

    Args:
        XA: DataFrame. Each record is matched against the nearest in XB.
        XB: DataFrame.

    Returns:
        DataFrame with columns for id_A (from XA), id_B (from XB), and dist.
        Each id_A maps to a single id_B, which is the nearest record from XB.
    """
    res = XA.apply(lambda x: nearest_record1(x, XB), axis=1)
    res['id_A'] = XA.index
    # id_B is sometimes returned as an object.
    res['id_B'] = res.id_B.astype(int)
    # Reorder columns.
    return res[['id_A', 'id_B', 'dist']]

Это также возвращает правильный результат:

nearest_record(XA, XB)
    id_A    id_B        dist
0      0       2    5.099020
1      1       2    4.472136
2      2       2    4.242641
0 голосов
/ 13 февраля 2019

Одним из способов является вычисление матрицы полного расстояния, затем melt и ее агрегирование с использованием nsmallest, которое возвращает индекс вместе со значением:

from scipy.spatial.distance import cdist

def nearest_record(XA, XB):
    """Get the nearest record in XA for each record in XB.

    Args:
        XA: DataFrame. Each record is matched against the nearest in XB.
        XB: DataFrame.

    Returns:
        DataFrame with columns for id_A (from XA), id_B (from XB), and dist.
        Each id_A maps to a single id_B, which is the nearest record from XB.
    """
    dist = pd.DataFrame(cdist(XA, XB)).reset_index().melt('index')
    dist.columns = ['id_A', 'id_B', 'dist']
    # id_B is sometimes returned as an object.
    dist['id_B'] = dist.id_B.astype(int)
    dist.reset_index(drop=True, inplace=True)
    nearest = dist.groupby('id_A').dist.nsmallest(1).reset_index()
    return nearest.set_index('level_1').join(dist.id_B).reset_index(drop=True)

Это показывает, что id_B 2является ближайшей записью к каждой из трех записей в XA:

nearest_record(XA, XB)

 id_A       dist id_B
0   0   5.099020    2
1   1   4.472136    2
2   2   4.242641    2

Однако, поскольку это включает в себя вычисление матрицы полного расстояния, она будет медленной или потерпит неудачу, когда XA и XBбольшой.Альтернатива, которая вычисляет ближайшее для каждой строки, скорее всего, будет быстрее.

...