У меня снова возникла странная проблема.Использование scipy pdist в кадре данных pandas (и) списки
Предположим, у меня есть следующие фиктивного кадра данных (путем демонстрации моей проблемы):
import numpy as np
import pandas as pd
import string
# Test data frame
N = 3
col_ids = string.letters[:N]
df = pd.DataFrame(
np.random.randn(5, 3*N),
columns=['{}_{}'.format(letter, coord) for letter in col_ids for coord in list('xyz')])
df
Это производит:
A_x A_y A_z B_x B_y B_z C_x C_y C_z
0 -1.339040 0.185817 0.083120 0.498545 -0.569518 0.580264 0.453234 1.336992 -0.346724
1 -0.938575 0.367866 1.084475 1.497117 0.349927 -0.726140 -0.870142 -0.371153 -0.881763
2 -0.346819 -1.689058 -0.475032 -0.625383 -0.890025 0.929955 0.683413 0.819212 0.102625
3 0.359540 -0.125700 -0.900680 -0.403000 2.655242 -0.607996 1.117012 -0.905600 0.671239
4 1.624630 -1.036742 0.538341 -0.682000 0.542178 -0.001380 -1.126426 0.756532 -0.701805
Теперь я хотел бы использовать scipy.spatial.distance.pdist
на этом кадре данных панд , Это оказывается довольно нетривиальным процессом. То, что pdist
- это вычисление расстояния между m точками с использованием евклидова расстояния (2-нормы) в качестве метрики расстояния между точками. Точки расположены как m n-мерные векторы строк в матрице X (source).
Итак, есть несколько вещей, которые нужно сделать для создания функции, которая работает с кадром данных pandas, так что может использоваться функция pdist. Вы заметите, что pdist удобен, когда количество точек становится очень большим. Я попытался сделать свой собственный, который работает для однострочного кадра данных, но я не могу заставить его работать, в идеале, во всем кадре данных сразу.
Вот моя попытка:.
from scipy.spatial.distance import pdist, squareform
import numpy as np
import pandas as pd
import string
def Euclidean_distance(df):
EcDist = pd.DataFrame(index=df.index) # results container
arr = df.values # Store data frame values into a numpy array
tag_list = [num for elem in arr for num in elem] # flatten numpy array into single list
tag_list_3D = zip(*[iter(tag_list)]*3) # separate list into length = 3 sub-lists, that pdist() can work with
EcDist = pdist(tag_list_3D) # the distance between m points using Euclidean distance (2-norm)
return EcDist
Сначала я начинаю мой создания контейнера результаты в виде панд, чтобы сохранить результат в вторых, я сохранить кадр панды данных как Numpy массива, для того, чтобы получить его в виде списка на следующем шаге. Он должен быть списком, потому что функция pdist
работает только с списками. При сохранении фрейма данных в массив он сохраняет его как список в списке. Это должно быть сглажено, которое сохраняется в переменной «tag_list». В-третьих, tag_list активируется в виде суб-списков длины три, так что координаты x, y и z могут быть получены для каждой точки, что может быть использовано для нахождения евклидова расстояния между всеми этими точками (в этом примере есть три точки: A, B и C, каждый из которых является трехмерным).
Как сказано, функция работает, если кадр данных является одной строкой, но при использовании функции в данном примере он вычисляет евклидово расстояние для 5x3 точек, что дает в общей сложности 105 расстояний. То, что я хочу сделать, это вычислить расстояния на строку (так что pdist должен работать только с вектором 1x3 за раз). Такое, что для этого примера будет выглядеть мои окончательные результаты что-то вроде этого:
dist_1 dist_2 dist_3
0 0.807271 0.142495 1.759969
1 0.180112 0.641855 0.257957
2 0.196950 1.334812 0.638719
3 0.145780 0.384268 0.577387
4 0.044030 0.735428 0.549897
(это только фиктивные номера, чтобы показать желаемую форму)
Поэтому как я могу получить свою функцию, чтобы применить к кадр данных по-разному? Или еще лучше, как я могу заставить его выполнить функцию во всем кадре данных сразу, а затем сохранить результат в новом фрейме данных?
Любая помощь будет очень признательна. Благодарю.
Можете ли вы уточнить, что именно вы хотите? Вы говорите, что для каждой строки вашего DataFrame вам нужна новая строка, содержащая попарные расстояния между тремя точками в этой строке? Вы, кажется, указываете, что хотите увеличить это для большего количества очков, но если вы добавите больше очков за строку, ваш DataFrame станет довольно громоздким. Почему бы не иметь отдельные строки для каждой точки, с дополнительным столбцом, который указывает «идентификатор группы»? – BrenBarn
Вы не можете получить то, что хотите от 'scipy.spatial.distance'. Я знаю, потому что я работаю над улучшением этого, что позволит делать то, что вам нужно, см. PR [здесь] (https://github.com/scipy/scipy/pull/3163). Может быть, в 0.14 ... – Jaime
@BrenBarn, Хорошо, предположим, что у меня есть матричный массив. Строки массива содержат 3d координаты для точек в пространстве, подобных этому [(x, y, z), ..., (x, y, z)]. Теперь я хочу функцию, которая вычисляет евклидовы расстояния между всеми этими точками в этой строке. Предположим, что я хочу сделать то же самое во всех строках матрицы. В моем случае у меня есть 12 очков за строку, поэтому будет 66 (n (n-1)/12) ребер, если мы рассмотрим точки как полный граф. Следовательно, мой вопрос заключается в следующем: как сделать такую функцию? – Astrid