5

次のデータフレームがあり、Item1からItem 2への移動を何回見たかを示しています。たとえば、AからBへの遷移が1つ、AからCへの遷移が2つ、CからAへの遷移が1つあります。


    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

2つの項目の差を計算したいので、新しく構築されたデータフレームは次のようになります

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

誰かがパンダを使用してそれを行う方法を知っていますか?最初の2列にインデックスを付ける必要があると思いますが、パンダはまったく新しいので、多くの問題に直面しています。ありがとう

編集重複するペアはありません。たとえば、a-> bを2回表示することはできません(ただし、もちろんb-> aを表示することはできます)

4

2 に答える 2

4

誰かがこれをより少ない行に単純化できると確信していますが、何が起こっているのかを明確にするために長い間残しておきました。一言で言えば、「Item1」が「Item2」よりもアルファベットの前にあるかどうかに基づいて、データフレームを2つの部分に分割します。次に、「Item1」と「Item2」を反転し、「Moves」を1つのピースとして無効にします。それらを接着して戻し、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
于 2013-02-21T18:18:22.200 に答える
1

これを行う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

これがほとんどの方法であり、あなたにとっては十分かもしれません。

目的の最終出力を取得するには、ハッキーな方法があります。

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

ただし、否定が完全に正しくないことに注意してください(CDではなくDCなどの間違った方法の場合)。

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
于 2013-02-21T18:08:10.520 に答える