Подтвердить что ты не робот

Как анализировать все повторяющиеся записи в этом Pandas DataFrame?

Я хотел бы иметь возможность вычислять описательную статистику по данным в Pandas DataFrame, но мне все равно, что дублируются записи. Например, скажем, у меня есть DataFrame, созданный с помощью

import pandas as pd
data={'key1':[1,2,3,1,2,3,2,2],'key2':[2,2,1,2,2,4,2,2],'data':[5,6,2,6,1,6,2,8]}
frame=pd.DataFrame(data,columns=['key1','key2','data'])
print frame


     key1  key2  data
0     1     2     5
1     2     2     6
2     3     1     2
3     1     2     6
4     2     2     1
5     3     4     6
6     2     2     2
7     2     2     8

Как вы можете видеть, строки 0,1,3,4,6 и 7 - все дубликаты (используя "key1" и "key2". Однако, если я индексирую этот DataFrame так:

frame[frame.duplicated(['key1','key2'])]

Я получаю

   key1  key2  data
3     1     2     6
4     2     2     1
6     2     2     2
7     2     2     8

(т.е. 1-я и 2-я строки не отображаются, потому что они не индексируются True с помощью дублированного метода).

Это моя первая проблема. Мои другие проблемы касаются того, как извлечь описательную статистику из этой информации. Забыв отсутствующий дубликат на данный момент, скажем, я хочу вычислить .min() и .max() для повторяющихся записей (чтобы я мог получить диапазон). Я могу использовать groupby и эти методы для объекта groupby следующим образом:

a.groupby(['key1','key2']).min()

который дает

           key1  key2  data
key1 key2                  
1    2        1     2     6
2    2        2     2     1

Данные, которые я хочу, здесь явно, но какой лучший способ для меня извлечь его? Как индексировать результирующий объект, чтобы получить то, что я хочу (это ключ1, key2, информация о данных)?

4b9b3361

Ответ 1

EDIT для Pandas 0,17 или новее:

Поскольку аргумент take_last метода duplicated() был устарел в пользу нового аргумента keep, поскольку Pandas 0.17, обратитесь к этому ответу за правильный подход:

  • Вызовите метод duplicated() с помощью keep=False, т.е. frame.duplicated(['key1', 'key2'], keep=False).

Поэтому для извлечения необходимых данных для этого конкретного вопроса достаточно:

In [81]: frame[frame.duplicated(['key1', 'key2'], keep=False)].groupby(('key1', 'key2')).min()
Out[81]: 
           data
key1 key2      
1    2        5
2    2        1

[2 rows x 1 columns]

Интересно, что это изменение в Pandas 0,17 может быть частично связано с этим вопросом, как указано в этой проблеме.


Для версий, предшествующих Pandas 0.17:

Мы можем играть с аргументом take_last метода duplicated():

take_last: boolean, по умолчанию False

Для набора различных повторяющихся строк отметьте все, кроме последней строки, как дублированные. Значение по умолчанию для всех, кроме первой строки, помечено.

Если мы установим take_last значение в True, мы будем отмечать все, кроме последней повторяющейся строки. Объединив это вместе со значением по умолчанию False, который обозначает все, кроме первой повторяющейся строки, позволяет отмечать все дублированные строки:

In [76]: frame.duplicated(['key1', 'key2'])
Out[76]: 
0    False
1    False
2    False
3     True
4     True
5    False
6     True
7     True
dtype: bool

In [77]: frame.duplicated(['key1', 'key2'], take_last=True)
Out[77]: 
0     True
1     True
2    False
3    False
4     True
5    False
6     True
7    False
dtype: bool

In [78]: frame.duplicated(['key1', 'key2'], take_last=True) | frame.duplicated(['key1', 'key2'])
Out[78]: 
0     True
1     True
2    False
3     True
4     True
5    False
6     True
7     True
dtype: bool

In [79]: frame[frame.duplicated(['key1', 'key2'], take_last=True) | frame.duplicated(['key1', 'key2'])]
Out[79]: 
   key1  key2  data
0     1     2     5
1     2     2     6
3     1     2     6
4     2     2     1
6     2     2     2
7     2     2     8

[6 rows x 3 columns]

Теперь нам просто нужно использовать методы groupby и min, и я считаю, что вывод находится в необходимом формате:

In [81]: frame[frame.duplicated(['key1', 'key2'], take_last=True) | frame.duplicated(['key1', 'key2'])].groupby(('key1', 'key2')).min()
Out[81]: 
           data
key1 key2      
1    2        5
2    2        1

[2 rows x 1 columns]

Ответ 2

Чтобы получить список всех дублированных записей с помощью Pandas версии 0.17, вы можете просто установить 'keep = False' в duplicated.

frame[frame.duplicated(['key1','key2'],keep=False)]

    key1  key2  data
0     1     2     5
1     2     2     6
3     1     2     6
4     2     2     1
6     2     2     2
7     2     2     8

Ответ 3

Здесь одно возможное решение для возврата всех дублированных значений в двух столбцах (т.е. строк 0, 1, 3, 4, 6, 7):

>>> key1_dups = frame.key1[frame.key1.duplicated()].values
>>> key2_dups = frame.key2[frame.key2.duplicated()].values
>>> frame[frame.key1.isin(key1_dups) & frame.key2.isin(key2_dups)]
   key1  key2  data
0     1     2     5
1     2     2     6
3     1     2     6
4     2     2     1
6     2     2     2
7     2     2     8

( Изменить: на самом деле метод df.duplicated(take_last=True) | df.duplicated() в ответе @Yoel более аккуратен.)

Чтобы запросить результаты вашей операции groupby, вы можете использовать loc. Например:

>>> dups = frame[frame.key1.isin(key1_dups) & frame.key2.isin(key2_dups)]
>>> grouped = dups.groupby(['key1','key2']).min()
>>> grouped
           data
key1 key2      
1    2        5
2    2        1

>>> grouped.loc[1, 2]
    data    5
Name: (1, 2), dtype: int64

В качестве альтернативы, верните grouped обратно в "нормальный" DataFrame, сбросив оба индекса:

>>> grouped.reset_index(level=0).reset_index(level=0)
   key2  key1  data
0     2     1     5
1     2     2     1