2017-08-02 19 views
6

Powiedzmy mam listę wartości,Jak skutecznie wypełnić niekompletną ramkę danych pandy składającą się z parujących kombinacji wartości z listy?

lst=['orange','apple','banana', 'grape', 'lemon'] 

Mam też dataframe pandy formularza, df:

Source  Destination  Weight 
orange  apple   0.4 
banana  orange   0.67 
grape  lemon   0.1 
grape  banana   0.5 

Wiersze są podzbiorem wszystkich par połączeń w LST. Pamiętaj, że każda kombinacja pojawia się najwyżej raz.

Co chcę to nowy dataframe gdzie pozostałe kombinacje są wypełniane o wartości 0.

Na przykład, new_df:

Source  Destination  Weight 
orange  apple   0.4 
banana  orange   0.67 
grape  lemon   0.1 
grape  banana   0.5 
orange  grape   0.0 
orange  lemon   0.0 
banana  lemon   0.0 

Kolejność nie robi różnicy.

Co to jest szybki sposób?

Odpowiedz

5
  • tworzę tablicę zestawów kombinacji
  • Potem to samo w odniesieniu do kombinacji, które już istnieją
  • używam np.in1d aby znaleźć te, które nie istnieją
  • Następnie dołączania nowa ramka danych z tymi, które jeszcze nie istnieją.

from itertools import combinations 

comb = np.array([set(x) for x in combinations(lst, 2)]) 
exst = df[['Source', 'Destination']].apply(set, 1).values 
new = comb[~np.in1d(comb, exst)] 

d1 = pd.DataFrame(
    [list(x) for x in new], 
    columns=['Source', 'Destination'] 
).assign(Weight=0.) 

df.append(d1, ignore_index=True) 

    Source Destination Weight 
0 orange  apple 0.40 
1 banana  orange 0.67 
2 grape  lemon 0.10 
3 grape  banana 0.50 
4 grape  orange 0.00 
5 orange  lemon 0.00 
6 apple  banana 0.00 
7 grape  apple 0.00 
8 apple  lemon 0.00 
9 banana  lemon 0.00 
+0

Może pójdę gdzie mój mózg bierze mnie. Zyskaj jedną odpowiedź, a następnie szukaj więcej ... patrząc teraz (-: – piRSquared

+0

Dziękuję za odpowiedź! Zauważam, że otrzymujemy duplikaty, na przykład, banan/pomarańcza ma wartość 0.67, ale inny wiersz - pomarańczowy/banan zostanie dodany o wartości 0,0. Czy istnieje sposób, aby nie dodawać tych wierszy? – Melsauce

+0

@Melsauce Nawet o tym nie myślałem ... Będę musiał naprawić lub wymyślić coś innego. kilka minut .. – piRSquared

2

Krok 1: Konwersja dataframe źródłowego do frozenset

In [350]: df = df.assign(Combinations=df.apply(lambda x: frozenset(x[:-1]), axis=1)).loc[:, ['Combinations', 'Weight']] 

Krok 2: Generowanie wszystkich możliwych kombinacji (import itertools pierwsze) przedmiotów z lst

In [352]: new_df = pd.DataFrame(list(itertools.combinations(lst, 2)), columns=['Source', 'Destination']) 

Krok 3: Scal w kombinacjach

In [358]: new_df = new_df.iloc[:, :2].apply(lambda x: frozenset(x), axis=1)\ 
         .to_frame().rename(columns={0 : "Combinations"})\ 
         .merge(df, how='outer').fillna(0) 

Krok 4: Przywróć do oryginalnej struktury

In [365]: new_df.apply(lambda x: pd.Series(list(x['Combinations'])), axis=1)\ 
       .rename(columns={0 : 'Source', 1 : 'Destination'})\ 
       .join(new_df['Weight']) 
Out[365]: 
    Source Destination Weight 
0 orange  apple 0.40 
1 orange  banana 0.67 
2 grape  orange 0.00 
3 orange  lemon 0.00 
4 apple  banana 0.00 
5 grape  apple 0.00 
6 apple  lemon 0.00 
7 grape  banana 0.50 
8 lemon  banana 0.00 
9 grape  lemon 0.10 
+0

Ten sam problem co mój ... OP chce, aby obojętność między '(" pomarańczowy "," jabłko ")' i '(" jabłko "," pomarańczowy ")' – piRSquared

+0

@piRSquared Co powiesz teraz? Musiałem ugryźć bullet.To jest naprawdę długo znoszone –

+0

Co stało się z bananem, pomarańczowym jest .67 – piRSquared

Powiązane problemy