Как сгруппировать по столбцу и посчитать количество категорий в других столбцах? - PullRequest
0 голосов
/ 11 ноября 2018

Предположим, у меня есть следующий фрейм данных:

    name        tags
0   abc (1990)  AB|A|BC
1   def (2000)  BC|AB
2   yz (1990)   A|AB

Значения в столбце tags разделены трубами. Кроме того, формат значений в столбце name похож на description (year). Я хочу подсчитать количество тегов для каждого года, чтобы получить объект Series, подобный этому:

year    
1990  A     2
      AB    2
      BC    1
2000  AB    1
      BC    1

Или его эквивалент как DataFrame:

    year    tags    count
0   1990    A       2
1   1990    AB      2
2   1990    BC      1
3   2000    AB      1
4   2000    BC      1

Однако у меня есть решение для этого, поскольку оно включает определение пользовательской функции для передачи методу apply, мне было интересно, существует ли более компактное или эффективное решение?

Вот мое текущее решение:

years = df['name'].str.slice(start=-5, stop=-1).rename('year')
new_df = df['tags'].str.split('|', expand=True).join(years)

def count_tags(g):
    return g.drop(columns=['year']).stack().value_counts()

new_df.groupby('year').apply(count_tags)

, что дает:

year    
1990  A     2
      AB    2
      BC    1
2000  AB    1
      BC    1
dtype: int64

P.S. Для меня не имеет значения, хранится ли year в виде строки или целого числа в результате.

1 Ответ

0 голосов
/ 11 ноября 2018

Использование:

new_df = (df.assign(year=lambda x: x['name'].str[-5:-1])
            .set_index('year')['tags']
            .str.split('|', expand=True)
            .stack()
            .reset_index(name='tags')
            .groupby(['year','tags'])
            .size()
            .reset_index(name='count'))
print (new_df)

   year tags  count
0  1990    A      2
1  1990   AB      2
2  1990   BC      1
3  2000   AB      1
4  2000   BC      1

Объяснение

  1. Для решения на одну строку сначала используйте assign для нового столбца с нарезкой
  2. Для индексации по year используйте set_index
  3. Затем split для DataFrame и изменение формы на stack для Series с MultiIndex
  4. Для столбцов из MultiIndex добавить reset_index
  5. Последний groupby и совокупность size, последний reset_index для столбца count

Другое решение:

from itertools import chain

tags = df['tags'].str.split('|')

df1 = pd.DataFrame({
    'tags' : list(chain.from_iterable(tags.values.tolist())), 
    'year' : df['name'].str[-5:-1].repeat(tags.str.len())
})

print (df1)
  tags  year
0   AB  1990
1    A  1990
2   BC  1990
3   BC  2000
4   AB  2000
5    A  1990
6   AB  1990

df2 = df1.groupby(['year','tags']).size().reset_index(name='count')
print (df2)
   year tags  count
0  1990    A      2
1  1990   AB      2
2  1990   BC      1
3  2000   AB      1
4  2000   BC      1

Объяснение

  1. Создание списков по split
  2. Получить длины списков по len
  3. Последний repeat столбцы и сплющивание
  4. groupby и совокупность size
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...