Уникальные комбинации значений в выбранных столбцах во фрейме данных и количестве панд

У меня есть данные в фрейме данных панд следующим образом:

df1 = pd.DataFrame({'A':['yes','yes','yes','yes','no','no','yes','yes','yes','no'],
                   'B':['yes','no','no','no','yes','yes','no','yes','yes','no']})

Итак, мои данные выглядят так

----------------------------
index         A        B
0           yes      yes
1           yes       no
2           yes       no
3           yes       no
4            no      yes
5            no      yes
6           yes       no
7           yes      yes
8           yes      yes
9            no       no
-----------------------------

Я хотел бы преобразовать его в другой фрейм данных. Ожидаемый результат может быть показан в следующем скрипте Python:

output = pd.DataFrame({'A':['no','no','yes','yes'],'B':['no','yes','no','yes'],'count':[1,2,4,3]})

Итак, мой ожидаемый результат выглядит следующим образом

--------------------------------------------
index      A       B       count
--------------------------------------------
0         no       no        1
1         no      yes        2
2        yes       no        4
3        yes      yes        3
--------------------------------------------

На самом деле, я могу найти все комбинации и подсчитать их, используя следующую команду: mytable = df1.groupby(['A','B']).size()

Однако оказывается, что такие комбинации находятся в одном столбце. Я хотел бы разделить каждое значение в комбинации на другой столбец, а также добавить еще один столбец для результата подсчета. Возможно ли это сделать? Могу ли я получить ваши предложения? Заранее спасибо.

6 ответов

Решение

Вы можете groupby на столбцы "А" и "В" и позвоните size а потом reset_index а также rename сгенерированный столбец:

In [26]:

df1.groupby(['A','B']).size().reset_index().rename(columns={0:'count'})
Out[26]:
     A    B  count
0   no   no      1
1   no  yes      2
2  yes   no      4
3  yes  yes      3

Обновить

Небольшое объяснение, группируя по 2 столбцам, это группирует строки, в которых значения A и B совпадают, мы называем size который возвращает количество уникальных групп:

In[202]:
df1.groupby(['A','B']).size()

Out[202]: 
A    B  
no   no     1
     yes    2
yes  no     4
     yes    3
dtype: int64

Итак, теперь, чтобы восстановить сгруппированные столбцы, мы называем reset_index:

In[203]:
df1.groupby(['A','B']).size().reset_index()

Out[203]: 
     A    B  0
0   no   no  1
1   no  yes  2
2  yes   no  4
3  yes  yes  3

Это восстанавливает индексы, но агрегация размеров превращается в сгенерированный столбец 0поэтому мы должны переименовать это:

In[204]:
df1.groupby(['A','B']).size().reset_index().rename(columns={0:'count'})

Out[204]: 
     A    B  count
0   no   no      1
1   no  yes      2
2  yes   no      4
3  yes  yes      3

groupby принимает арг as_index который мы могли бы установить False так что это не делает сгруппированные столбцы индексом, но это генерирует series и вам все равно придется восстанавливать индексы и тд....

In[205]:
df1.groupby(['A','B'], as_index=False).size()

Out[205]: 
A    B  
no   no     1
     yes    2
yes  no     4
     yes    3
dtype: int64

В Pandas 1.1.0 вы можете использовать метод value_counts с DataFrames:

      df.value_counts() # or df[['A', 'B']].value_counts()

Результат:

      A    B
yes  no     4
     yes    3
no   yes    2
     no     1
dtype: int64

Преобразование индекса в столбцы и сортировка по количеству значений:

      df.value_counts(ascending=True).reset_index(name='count')

Результат:

           A    B  count
0   no   no      1
1   no  yes      2
2  yes  yes      3
3  yes   no      4

Основываясь на принятом ответе и комментарии @Bryan P о различиях между count() и size() , я выбрал count() для более чистого кода, как показано ниже:

      df1.groupby(['A','B']).count().reset_index()

Немного связанный, я искал уникальные комбинации, и я придумал этот метод:

def unique_columns(df,columns):

    result = pd.Series(index = df.index)

    groups = meta_data_csv.groupby(by = columns)
    for name,group in groups:
       is_unique = len(group) == 1
       result.loc[group.index] = is_unique

    assert not result.isnull().any()

    return result

И если вы хотите только утверждать, что все комбинации уникальны:

df1.set_index(['A','B']).index.is_unique

Я не проверял это на время, но попробовать было весело. В основном преобразуйте два столбца в один столбец кортежей. Теперь преобразуйте это в фрейм данных, выполните value_counts(), который находит уникальные элементы и подсчитывает их. Снова поиграйте с zip и расставьте столбцы в нужном вам порядке. Вы, вероятно, можете сделать шаги более элегантными, но для меня работа с кортежами кажется более естественной для этой проблемы.

b = pd.DataFrame({'A':['yes','yes','yes','yes','no','no','yes','yes','yes','no'],'B':['yes','no','no','no','yes','yes','no','yes','yes','no']})

b['count'] = pd.Series(zip(*[b.A,b.B]))
df = pd.DataFrame(b['count'].value_counts().reset_index())
df['A'], df['B'] = zip(*df['index'])
df = df.drop(columns='index')[['A','B','count']]

Поместите очень хороший ответ @EdChum в функцию count_unique_index. Этот уникальный метод работает только с сериями панд, но не с фреймами данных. Функция ниже воспроизводит поведение уникальной функции в R:

unique возвращает вектор, фрейм данных или массив, например x, но с удаленными повторяющимися элементами / строками.

И добавляет количество вхождений по запросу OP.

df1 = pd.DataFrame({'A':['yes','yes','yes','yes','no','no','yes','yes','yes','no'],                                                                                             
                    'B':['yes','no','no','no','yes','yes','no','yes','yes','no']})                                                                                               
def count_unique_index(df, by):                                                                                                                                                 
    return df.groupby(by).size().reset_index().rename(columns={0:'count'})                                                                                                      

count_unique_index(df1, ['A','B'])                                                                                                                                              
     A    B  count                                                                                                                                                                  
0   no   no      1                                                                                                                                                                  
1   no  yes      2                                                                                                                                                                  
2  yes   no      4                                                                                                                                                                  
3  yes  yes      3
Другие вопросы по тегам