2013-02-21 56 views
5

我有以下數據框,其中顯示了從Item1到Item 2的移動次數。例如,從A到B有2個從A到C的轉換,1從C到A計算數據框中特定列的成對差異


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 

我想計算兩個項之間的差,因此一個新構造的數據幀將是以下

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

有沒有人有任何想法如何做到這一點使用熊貓?我想我需要對前兩欄進行索引,但我在熊貓中頗爲新穎,而且我面臨很多困難。 感謝

編輯 不能有任何重複pairs.For例如你不能看到兩次A-> B(當然你可以看到的B-> A)

+0

重要的是你首先看到的過渡方向是否被保留,或者是否有'B C -5'的行是可以接受的? – DSM 2013-02-21 16:27:29

+0

這不是那麼重要,但我想它是一個優先選擇刪除第一次遇到兩個轉換還是第二個轉換的問題。 – BigScratch 2013-02-21 16:43:50

回答

3

我敢肯定有人可以簡化這一行到更少的行,但我已經離開它很長時間來澄清發生了什麼。簡而言之,根據'Item1'是否比'Item2'更早,將數據框分成兩部分。然後翻轉'項目1'和'項目2',否定'移動'爲一塊。將它們粘在一起並使用groupby函數來聚合行。

>>> 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

謝謝!這個答案對我來說似乎相當優雅 - 我已經設法使用列表來做這件事,但是我正在循環查看每一對的字典以找到相反的對,效率相當低 – BigScratch 2013-02-22 10:14:37

+0

您的建議編輯是一個很好的編輯。我不確定爲什麼會被別人拒絕,但在被3人拒絕後,我無法「批准」它。我做了編輯。 – 2013-02-22 17:34:48

1

下面是做這件事:

首先創建一個只包含Item1和Item2的字符串的行。

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是(字母)順序離開它,否則切換後,否定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 

這是大多數的方式,並可以爲你就夠了。

以獲得所需的最終輸出一個hackey方式可以是:

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 

但是,請注意否定是不完全正確(對周圍的人如DC而非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