Mam plik Excel z 100 kolumnami z 1000 wpisów. Każdy z tych wpisów może przyjmować 3 konkretne wartości (0,8, 0,0 i 0,37) Chcę policzyć liczbę niedopasowania między każdą kombinacją wpisu dwóch kolumn.

Na przykład, arkusz Excel poniżej przedstawia niedopasowanie między kolumnami:

|---------------------|------------------|---------------------|---------------|
|      Column 1       |     Column 2     |      Column 3       |     Mismatch  |
|---------------------|------------------|---------------------|---------------|
|          0.37       |         0.8      |          0.0        |         3     |
|---------------------|------------------|---------------------|---------------|
|          0.0        |         0.0      |          0.8        |         2     |
|---------------------|------------------|---------------------|---------------|

Najpierw porównujemy kolumnę 1 przeciwko kolumnie 2. Ponieważ istnieje różnica między pierwszymi wierszami, dodamy 1 do odpowiedniego wiersza kolumny niedopasowania. Powtarzamy to do kolumny 1 VS kolumna 3, a następnie kolumna 2 vs kolumna 3. więc musimy iterować każdą unikalną kombinację dwóch kolumn.

Brute siłowanie sposobem robienia tego jest zagnieżdżona pętla, która iteruje na dwie kolumny na raz. Zastanawiałem się, czy istnieje szansa w Panda-y.

1
Harshavardhan Ramanna 1 marzec 2019, 04:58

2 odpowiedzi

Najlepsza odpowiedź

Ponieważ sumować kombinacje para, jest to samo, co sprawdzanie pierwszej kolumny na drugim przez ostatnie kolumny, drugi przeciw trzecim przez ostatnie i tak dalej. Sprawdzanie N-1 (N Liczba kolumn) Zwydatności przeciwko DataFrame i sumowanie będą dość szybsze niż sprawdzanie NC2 poszczególne łączenia kolumn, zwłaszcza z dużą liczbą kolumn :

from functools import reduce

reduce(lambda x,y: x+y, [df.iloc[:, i+1:].ne(df.iloc[:, i], axis=0).sum(1) 
                          for i in range(len(df.columns)-1)])
0    3
1    2
dtype: int64

Niektóre czasy z wielkością danych

import numpy as np
import pandas as pd
from itertools import combinations

np.random.seed(123)
df = pd.DataFrame(np.random.choice([0, 0.8, 0.37], (1000,100)))

%timeit reduce(lambda x, y: x+y, [df.iloc[:, i+1:].ne(df.iloc[:, i], axis=0).sum(1) for i in range(len(df.columns)-1)])
#157 ms ± 659 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit pd.concat([df[x[0]]!=df[x[1]] for x in list( combinations(L, 2))],axis=1).sum(1)
#1.55 s ± 9.93 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Możesz nieznacznie uzyskać za pomocą numpy i podsumowując wartości, chociaż tracisz indeks:

%timeit np.sum([df.iloc[:, i+1:].ne(df.iloc[:, i], axis=0).sum(1).to_numpy() for i in range(len(df.columns)-1)], axis=0)
#139 ms ± 715 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
1
ALollz 14 marzec 2019, 20:48

To jest to, co radzę sobie z tym problemem

from itertools import combinations
L = df.columns.tolist()
pd.concat([df[x[0]]!=df[x[1]] for x in list( combinations(L, 2))],axis=1).sum(1)
0    3
1    2
dtype: int64
3
BENY 1 marzec 2019, 02:09