#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.