2013-02-21 16 views
5

Mam następującą ramkę danych, w której pokazuję, ile razy widziałem przejście z elementu 1 do elementu 2. Na przykład występuje jedno przejście z punktu A do punktu B, od drugiego punktu do punktu A 1 z C na AObliczyć różnicę parami względem określonych kolumn w ramce danych


Item1 Item2 Moves 
    1 A  B  1 
    2 A  C  2 
    3 B  D  3 
    4 C  A  1 
    5 C  B  5 
    6 D  B  4 
    7 D  C  1 

ja jak obliczenie różnicy pomiędzy dwoma elementami, a więc nowo budowane Dataframe byłby następujący

Item1 Item2 Moves 
    1 A  B  1 
    2 A  C  1 
    3 B  D  -1 
    4 C  B  5 
    5 D  C  1 

Czy ktoś ma pomysł, jak to zrobić, używając Pand? Sądzę, że muszę indeksować pierwsze dwie kolumny, ale jestem całkiem nowy w Pandach i mam wiele trudności. Dzięki

EDIT nie może być każdy duplikat pairs.For przykład nie można zobaczyć dwa razy a-> b (ale można oczywiście zobaczyć b-> a)

+0

Czy dla ciebie ważne jest, aby pierwszy widoczny kierunek przejścia został zachowany, czy też mógłby być dozwolony rząd z 'B C -5'? – DSM

+0

To nie jest takie ważne, ale myślę, że jest to kwestia wyboru usunięcia pierwszego kontaktu z dwóch przejść lub drugiego. – BigScratch

Odpowiedz

3

Jestem pewien, że ktoś mógłby uprościć to do mniejszej liczby wierszy, ale zostawiłem go na długo, aby pomóc wyjaśnić, co się dzieje. W skrócie, podziel ramkę danych na dwie części w oparciu o to, czy "Element 1" jest wcześniej w alfabecie niż "Element 2". Następnie odwróć "Pozycja 1" i "Pozycja 2" i zaneguj "Ruchy" na jedną sztukę. Połącz je ponownie i użyj funkcji groupby do agregowania wierszy.

>>> df 
    Item1 Item2 Moves 
0  A  B  1 
1  A  C  2 
2  B  D  3 
3  C  A  1 
4  C  B  5 
5  D  B  4 
6  D  C  1 
>>> swapidx = df['Item1'] < df['Item2'] 
>>> df1 = df[swapidx] 
>>> df2 = df[swapidx^True] 
>>> df1 
    Item1 Item2 Moves 
0  A  B  1 
1  A  C  2 
2  B  D  3 
>>> df2 
    Item1 Item2 Moves 
3  C  A  1 
4  C  B  5 
5  D  B  4 
6  D  C  1 
>>> df2[['Item1', 'Item2']] = df2[['Item2', 'Item1']] 
>>> df2['Moves'] = df2['Moves']*-1 
>>> df2 
    Item1 Item2 Moves 
3  A  C  -1 
4  B  C  -5 
5  B  D  -4 
6  C  D  -1 
>>> df3 = df1.append(df2) 
>>> df3.groupby(['Item1', 'Item2'], as_index=False).sum() 
    Item1 Item2 Moves 
0  A  B  1 
1  A  C  1 
2  B  C  -5 
3  B  D  -1 
4  C  D  -1 
+0

Dziękujemy! Ta odpowiedź wydaje mi się dość elegancka - udało mi się to zrobić za pomocą list, ale przeglądałem w słowniku każdą parę, aby znaleźć przeciwną parę, co jest dość nieefektywne. – BigScratch

+0

Twoja sugerowana edycja była dobra. Nie wiem, dlaczego został odrzucony przez innych, ale nie mogłem go "zatwierdzić" po odrzuceniu przez 3 osoby. Dokonałem edycji. –

1

Oto jeden ze sposobów, aby to zrobić:

Najpierw utwórz wiersz, który zawiera ciąg znaków dla pozycji 1 i pozycji 2.

In [11]: df['Items'] = df.apply(lambda row: row['Item1'] + row['Item2'], axis=1) 

In [12]: df 
Out[12]: 
    Item1 Item2 Moves Items 
1  A  B  1 AB 
2  A  C  2 AC 
3  B  D  3 BD 
4  C  A  1 CA 
5  C  B  5 CB 
6  D  B  4 DB 
7  D  C  1 DC 

Items i jeśli jest (w kolejności alfabetycznej) kolejność pozostawić go jeszcze włączyć go i negować Moves:

In [13]: df[['Items','Moves']] = df.apply(lambda row: (row[['Items', 'Moves']]) 
                 if row['Items'][0] <= row['Items'][1] 
                 else (row['Items'][::-1], -row['Moves']), 
              axis=1) 

In [14]: df 
Out[14]: 
    Item1 Item2 Moves Items 
1  A  B  1 AB 
2  A  C  2 AC 
3  B  D  3 BD 
4  C  A  -1 AC 
5  C  B  -5 BC 
6  D  B  -4 BD 
7  D  C  -1 CD 

In [15]: g = df.groupby('Items') 

In [16]: g.sum() 
Out[16]: 
     Moves 
Items  
AB   1 
AC   1 
BC  -5 
BD  -1 
CD  -1 

Która jest najbardziej z drogi, i może być dla ciebie za mało.

Aby uzyskać pożądany wynik końcowy hackey sposób mogą być:

In [17]: df1 = g.first() # the first row in each group 

In [18]: df1.Moves = g.sum() 

In [19]: df2 = df1.reset_index(drop=True) 

In [20]: df2 
Out[20]: 
    Item1 Item2 Moves 
0  A  B  1 
1  A  C  1 
2  C  B  -5 
3  B  D  -1 
4  D  C  -1 

jednak zauważyć negacja nie jest całkiem w porządku (dla tych niewłaściwy sposób wokół np DC zamiast CD):

In [21]: df2.Moves = df2.apply(lambda row: row['Moves'] 
              if row['Item1'] <= row['Item2'] 
              else -row['Moves'], 
           axis=1) 

In [22]: df2 
Out[22]: 
    Item1 Item2 Moves 
0  A  B  1 
1  A  C  1 
2  C  B  5 
3  B  D  -1 
4  D  C  1 
Powiązane problemy