Мне нужно создать фрейм данных, содержащий манхэттенское расстояние между двумя фреймами данных с одинаковыми столбцами, и мне нужно, чтобы индексы каждого фрейма данных были индексом и именем столбца, поэтому, например, скажем, у меня есть эти два фрейма данных:
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 строки, называемые индексами, которые я получаю при создании нового фрейма данных, а также я получаю сообщение об ошибке независимо от того, что я делаю в строке расчета Манхэттена, может ли кто-нибудь помочь мне здесь, пожалуйста?
В вашем коде есть очень небольшая проблема, то есть доступ к значениям в 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. Обратите внимание, что его можно сделать более эффективным, но для демонстрации я использовал это решение.
Привет @bendush, решение не использует никаких функций, связанных с векторизацией. Он использует только метод применения в пандах, который, проще говоря, эффективно перебирает фрейм данных по любой оси, обрабатывает функцию для каждого элемента и, следовательно, дает выходной фрейм данных. Чтобы лучше понять и сравнить методы векторизации, обратитесь сюда: engineering.upside.com/…
Спасибо! Я не понял, что такое строка переменной, которую вы получаете в xtrain_distance, если вы можете объяснить это, я был бы признателен!
Конечно. Когда вы используете атрибут применения в пандах, он принимает имя функции в качестве аргумента. И затем он передает каждую строку (если ось = 1) или столбец (если ось = 0) кадра данных этой функции в качестве входных данных. В нашем случае все строки фрейма данных x_test передаются функции одна за другой, и на выходе получается серия ответов функции pandas.
Спасибо, это сработало. Я проголосовал, но это не отображается :/. Также спасибо за совет по эффективному решению! но я не уверен, что смогу использовать его для своего задания, поскольку нам не разрешалось использовать какую-либо функцию, которая выполняет какую-либо из функций векторного расстояния, не уверен, что ваше решение использует что-либо, но был бы рад узнать