Фрейм данных Groupby pandas на основе пользовательского списка возможных значений

python #pandas #pandas-groupby

#python #pandas #pandas-groupby

Вопрос:

Я хочу сгруппировать значения в двух столбцах. Я знаю все возможные значения в столбцах. В некоторых примерах данных определенные значения в столбцах a отсутствуют. Я все равно хотел бы, чтобы на выходе groupby было указано, что длина группы равна нулю.

           s      a  
0  Michaels     FS
1  Michaels     FS
2  Michaels    fds
3  Michaels   fnfe
4  Rogers       FS
5  Rogers      fds
6  Rogers      fds
7  Rogers      ssn
 

Я хочу сгруппировать как s, так и a.

 df.groupby(by=["s", "a"]).size()
 

Если вы посмотрите на данные -образцы fnfe и ssn отсутствуют как для Майклса, так и для Роджерса. Таким образом, для Michaels-ssn и Rogers-fnfe не будет вывода.

Я нашел способ обойти это с помощью:

df.groupby(by=[«s», «a»]).size().unstack().fillna(0).stack()

Но потом я подумал, что существует вероятность того, что будет несколько значений a, которые не будут ни в одной из групп, но я все равно их на выходе с их значением, равным нулю. Столбец s не имеет таких требований.

Допустим, есть другое значение для столбца «a» «adg», которого нет ни в одном примере. Желаемый результат будет:

 s         a   
Michaels  FS      2
          fds     1
          fnfe    1
          ssn     0
          adg     0
Rogers    FS      1
          fds     2
          ssn     1
          fnfe    0
          adg     0
 

Ответ №1:

Используйте Series.reindex с MultiIndex.from_product помощью и добавляйте значения в списки с уникальными значениями:

 out = df.groupby(by=["s", "a"]).size()

s = df['s'].unique()
a = df['a'].unique().tolist()   ['adg']

out = out.reindex(pd.MultiIndex.from_product([s, a], names=['s','a']), fill_value=0)

print (out)
s         a   
Michaels  FS      2
          fds     1
          fnfe    1
          ssn     0
          adg     0
Rogers    FS      1
          fds     2
          fnfe    0
          ssn     1
          adg     0
dtype: int64
 

Ваше решение:

 a = df['a'].unique().tolist()   ['adg']

out = (df.groupby(by=["s", "a"]).size()
         .unstack(fill_value=0)
         .reindex(a, fill_value=0, axis=1)
         .stack())

print (out)
s         a   
Michaels  FS      2
          fds     1
          fnfe    1
          ssn     0
          adg     0
Rogers    FS      1
          fds     2
          fnfe    0
          ssn     1
          adg     0
dtype: int64
 

Другая идея заключается в использовании Categorical :

 df['a'] = pd.Categorical(df['a'], categories=df['a'].unique().tolist()   ['adg'])

out = df.groupby(by=["s", "a"]).size()
print (out)
s         a   
Michaels  FS      2
          fds     1
          fnfe    1
          ssn     0
          adg     0
Rogers    FS      1
          fds     2
          fnfe    0
          ssn     1
          adg     0
dtype: int64
 

Комментарии:

1. Спасибо, действительно хорошие решения. Единственное отличие, которое я использовал, заключалось в том, что я использовал наборы для определения категорий из-за того, что не знал наверняка, что значение будет отсутствовать.