Уникальные комбинации значений в выбранных столбцах во фрейме данных и количестве панд
У меня есть данные в фрейме данных панд следующим образом:
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