2013-02-21 2 views
5

У меня есть следующий фреймворк, где я показываю, сколько раз я видел переход от Item1 к Item 2. Например, есть один переход от A к B, 2 от A до C , 1 от с к АВычислить попарное отличие от конкретных столбцов в dataframe


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 

Я хотел бы вычислить разность между двумя элементами, таким образом, вновь построенные Dataframe будут следующим

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

Кто-нибудь знает, как это сделать с помощью Pandas? Наверное, мне нужно индексировать первые две колонки, но я совершенно новый в Pandas, и у меня много трудностей. Благодаря

EDIT Там не может быть какой-либо дубликат pairs.For Например, вы не можете увидеть дважды a-> б (но вы, конечно, можете увидеть b-> а)

+0

Важно ли вам, чтобы начальное направление перехода сохранилось, или допустима ли строка с 'B C -5'? – DSM

+0

Это не так важно, но я думаю, что это вопрос предпочтения либо удаления первой встречи двух переходов, либо второй. – BigScratch

ответ

3

Я уверен, что кто-то может упростить это до меньшего количества строк, но я оставил его долго, чтобы помочь прояснить, что происходит. В двух словах разделите блок данных на две части, основываясь на том, является ли «Item1» раньше в алфавите, чем «Item2». Затем переверните «Item1» и «Item2» и отмените «Перемещения» для одной части. Слейте их обратно вместе и используйте функцию 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

+0

Ваше предлагаемое редактирование было хорошим. Я не уверен, почему его отвергли другие, но я не смог «одобрить» его после того, как он был отклонен тремя людьми. Я сделал редактирование. –

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 
Смежные вопросы