создание нового фрейма данных с расстоянием до Манхэттена в python

#python #pandas #dataframe

#python #pandas #фрейм данных

Вопрос:

Мне нужно создать фрейм данных, содержащий расстояние манхэттена между двумя фреймами данных с одинаковыми столбцами, и мне нужно, чтобы индексы каждого фрейма данных были индексом и именем столбца, поэтому, например, допустим, у меня есть эти два фрейма данных:

 x_train :
index a b c
11    2 5 7
23    4 2 0
312   2 2 2
x_test : 
index a b c
22    1 1 1
30    2 0 0
 

таким образом, столбцы совпадают, но размер и индексы не совпадают, ожидаемый фрейм данных будет выглядеть следующим образом:

 dist_dataframe:
index 11 23 312
22    11 5  3
30    12 4  4
 

и то, что у меня есть прямо сейчас, это:

 def manhattan_distance(a, b):
    return sum(abs(e1-e2) for e1, e2 in zip(a,b))

def calc_distance(X_test,X_train):
    dist_dataframe = pd.DataFrame(index=X_test.index,columns = X_train.index)
    for i in X_train.index:
        for j in X_test.index:
            dist_dataframe.loc[i,j]=manhattan_distance(X_train.loc[[i]],X_test.loc[[j]])
    return dist_dataframe
 

что я получаю из имеющегося у меня кода, так это этот фрейм данных:

 dist_dataframe:
index
index 11  23  312
22    NaN NaN NaN
30    NaN NaN NaN
 

Я получаю правильный размер фрейма данных, за исключением того, что в нем есть 2 строки, называемые индексами, которые я получаю при создании нового фрейма данных, а также я получаю сообщение об ошибке независимо от того, что я делаю в строке вычисления Манхэттена, может кто-нибудь помочь мне здесь, пожалуйста?

Ответ №1:

Проблема в вашем коде

В вашем коде есть очень небольшая проблема, то есть доступ к значениям в dist_dataframe . Итак, вместо dist_dataframe.loc[i,j] этого вы должны изменить порядок i и j и сделать его похожим dist_dataframe.loc[j,i]

Более эффективное решение

Это будет работать нормально, но поскольку вы новый участник, я также хотел бы отметить эффективность вашего кода. Всегда старайтесь заменять циклы встроенными функциями pandas. Поскольку они написаны на C, это делает их намного быстрее. Итак, вот более эффективное решение:

 def manhattan_distance(a, b):
    return sum(abs(e1-e2) for e1, e2 in zip(a,b))

def xtrain_distance(row):
    distances = {}
    for i,each in x_train.iterrows():
        distances[i] = manhattan_distance(each,row)
    return distances

result = x_test.apply(xtrain_distance, axis=1)

# converting into dataframe
pd.DataFrame(dict(result)).transpose()
 

Он также выдает тот же результат, что и в вашем примере, и вы не видите никакой разницы во времени. Но при запуске с большим размером (те же данные масштабируются более чем в 20 раз), т.Е. 60 x_train выборок и 40 x_test выборок, вот разница во времени:

Ваше решение заняло: 929 ms

Это решение потребовало: 207 ms

Он стал в 4 раза быстрее, просто исключив один цикл for. Обратите внимание, что это можно сделать более эффективным, но для демонстрации я использовал это решение.

Комментарии:

1. Спасибо, это сработало. Я проголосовал, но он этого не показывает:/. Также спасибо за подсказку по эффективному решению! но я не уверен, что смогу использовать его для своего задания, поскольку нам не разрешили использовать какую-либо функцию, которая выполняет любую из функций векторного расстояния, не уверен, использует ли ваше решение какое-либо из них, был бы рад узнать

2. Привет @bendush, решение не использует никаких функций, связанных с векторизацией. В pandas используется только метод apply, который, проще говоря, эффективно перебирает фрейм данных вдоль любой оси, обрабатывает функцию для каждого элемента и, следовательно, выдает выходной фрейм данных. Чтобы лучше понять и сравнить с методами векторизации, обратитесь к этому: engineering.upside.com /…

3. Спасибо! Я не понял, что такое переменная строка, которую вы получаете в xtrain_distance, если вы можете, пожалуйста, объяснить это, я был бы признателен!

4. Конечно. Когда вы используете атрибут apply в pandas, он принимает имя функции в качестве аргумента. И затем он передает каждую строку (если axis = 1) или столбец (если axis = 0) фрейма данных в эту функцию в качестве входных данных. В нашем случае все строки фрейма данных x_test передаются одна за другой в функцию, а на выходе получается серия ответов функции pandas.