#python #pandas #numpy #matrix #distance
Вопрос:
У меня есть фрейм данных, который выглядит следующим образом:
data = pd.DataFrame({'id':[1,1,1,2,2,2,3,3,3],
'age':[20, 21,18,54,23,11, 19, 18,12],
'experience':[5,4,3,8,2,11,2,8,6]},columns=['id','age','experience'])
id age experience
0 1 20 5
1 1 21 4
2 1 18 3
3 2 54 8
4 2 23 2
5 2 11 11
6 3 19 2
7 3 18 8
8 3 12 6
Я использую пользовательскую функцию расстояния под названием dtw_path, которая вычисляет расстояние между кортежами. Я не буду вдаваться в то, как именно эта функция вычисляет расстояние, поскольку это сложная процедура, но она просто выводит скалярное значение расстояния между кортежами.
Кортеж формируется следующим образом:
data['age_exp'] = data[['age', 'experience']].apply(tuple, axis=1)
id age experience age_exp
0 1 20 5 (20, 5)
1 1 21 4 (21, 4)
2 1 18 3 (18, 3)
3 2 54 8 (54, 8)
4 2 23 2 (23, 2)
5 2 11 11 (11, 11)
6 3 19 2 (19, 2)
7 3 18 8 (18, 8)
8 3 12 6 (12, 6)
Поэтому для приведенного выше фрейма данных, если мне нужно рассчитать расстояние между идентификаторами 1 и 2, я бы рассчитал расстояние следующим образом:
data1 = data[data['id']==1]
data1 = np.array(data1['age_exp'].tolist())
data1
array([[20, 5],
[21, 4],
[18, 3]])
data2 = data[data['id']==2]
data2 = np.array(data2['age_exp'].tolist())
data2
array([[54, 8],
[23, 2],
[11, 11]])
dtw_path(data1,data2)[1]
1.5
Мне нужна помощь в том, как перебрать фрейм данных и создать матрицу расстояний для столбца идентификатора, т. е. что-то вроде этого
1 2 3
1 0 1.5 2
2 1.5 0 2.3
3 2 2.3 0
Комментарии:
1. что именно это
dtw_path
такое ?
Ответ №1:
В вашем вопросе неясно, что dtw_path
это такое. Я использовал здесь tslearn.metrics.dtw_path
, что дает мне разные результаты. Тем не менее, обоснование должно быть тем же самым.
Давайте сначала немного изменим исходный фрейм данных:
data2 = (data.groupby('id')
.apply(lambda x: np.array(list(zip(x['age'], x['experience']))))
).to_frame()
0
id
1 [[20, 5], [21, 4], [18, 3]]
2 [[54, 8], [23, 2], [11, 11]]
3 [[19, 2], [18, 8], [12, 6]]
nb. Для следующего шага он должен быть двумерным (фрейм данных), поэтому .to_frame()
Затем примените свою dtw_path
функцию, используя scipy.spatial.distance.pdist
, которая может принимать произвольную функцию расстояния с помощью параметра metric
и сохранять только второй элемент вывода. Наконец, измените форму вывода в виде квадратной матрицы, используя scipy.spatial.distance.squareform
:
squareform(pdist(data2, metric=lambda x,y: dtw_path(x[0], y[0])[1]))
выход:
array([[ 0. , 35.86084215, 8.94427191],
[35.86084215, 0. , 36.7151195 ],
[ 8.94427191, 36.7151195 , 0. ]])
Комментарии:
1. Это идеально , и да, значение вашего dtw_path правильное, я только что изменил его в иллюстративных целях.