Учитывая некоторые строки категориальных данных, я хочу вычислить парную матрицу с количеством различий между этими строками.
Например, сравнение строки со значениями [1, 0, 0, 1]
со строкой со значениями [0, 0, 1, 1]
даст результирующее значение 2, так как индексы 0 и 2 различаются.
Я хочу сделать матрицу, показывающую каждую парную комбинацию строк. Я написал код для этого, однако он очень неэффективен для больших данных. Я знаю, что должен быть способ сделать это более эффективно, потому что только верхняя половина этой матрицы действительно должна быть рассчитана.
Однако я не знаю, как перевести его на код. Вот что я имею до сих пор:
shortened = pd.DataFrame(
[{'c1':1, 'c2':0, 'c3':0}, {'c1':1,'c2':1, 'c3':0}, {'c1':0,'c2':0, 'c3':1}]
)
distm = [[""]+ list(shortened.index)]
found = {}
for index,row in shortened.iterrows():
newrow = [index]
for i2,r2 in shortened.iterrows():
if((i2,index) in found):
newrow.append(found[(i2,index)])
continue
if(index == i2):
newrow.append(0)
continue
summeddif = sum(i != j for i, j in zip(row, r2))
newrow.append(summeddif)
found[(index,i2)] = summeddif
distm.append(newrow)
Таким образом, с примером dataframe, получается правильный вывод:
| 0 1 2
---------
0 | 0 1 2
1 | 1 0 3
2 | 2 3 0
Однако с очень большим вкладом это берет навсегда. Есть ли элегантный способ перебирать только верхнюю половину и просто копировать до нижней половины, поэтому мне не нужно делать ненужные сравнения? Или нет другого способа улучшить это через панды?
Используйте широковещательный XOR.
(shortened.values ^ shortened.values[:, None]).sum(2)
array([[0, 1, 2],
[1, 0, 3],
[2, 3, 0]])
XOR - самый простой (и самый быстрый) способ проверки того, являются ли два бита одинаковыми. Это должно работать до тех пор, пока ваш вход двоичный.
Обратите внимание, что это интенсивность памяти, особенно для очень больших кадров, с возможностью OOM на ~ 1M строках.
sum(axis=2)
, что мне нужно было сделать, чтобы получить ожидаемый результат.