Решение:
- Создание логической маски, которая выбирает верхние треугольные недиагональные значения из начальной матрицы
- Преобразуйте эту маску (с
.reshape()
) и исходную матрицу (с .stack()
) в векторы столбцов одинакового размера
- Используйте логическое индексирование, чтобы выбрать нужные вам строки.
Пример:
import pandas as pd
import numpy as np
np.random.seed(1)
# Example data
df = pd.DataFrame(pd.np.random.randint(0, 4, size=(5, 5)),
index=[10, 50, 30, 2488, 9416],
columns=[10, 50, 30, 2488, 9416])
# Quick and dirty method to make the example data symmetric
df = df + df.T
df
10 50 30 2488 9416
10 2 4 0 0 5
50 4 6 2 5 1
30 0 2 0 4 3
2488 0 5 4 4 0
9416 5 1 3 0 6
# To select the upper-triangular, non-diagonal entries,
# take a *lower*-triangular mask, np.tril,
# and negate it with ~.
mask = (~np.tril(np.ones(df.shape)).astype('bool'))
mask
array([[False, True, True, True, True],
[False, False, True, True, True],
[False, False, False, True, True],
[False, False, False, False, True],
[False, False, False, False, False]])
# Prepare to select rows from the stacked df
mask = mask.reshape(df.size)
# Stack the columns of the starting matrix into a MultiIndex,
# which results in a MultiIndexed Series;
# select the upper-triangular off-diagonal rows;
# reset the MultiIndex levels into columns
df.stack()[mask].reset_index().rename({'level_0': 'UserID_row',
'level_1': 'UserID_col',
0: 'Occurrence'}, axis=1)
UserID_row UserID_col Occurrence
0 10 50 4
1 10 30 0
2 10 2488 0
3 10 9416 5
4 50 30 2
5 50 2488 5
6 50 9416 1
7 30 2488 4
8 30 9416 3
9 2488 9416 0