pd.get_dummies() с разделителем и подсчетами

#python #pandas #vectorization

#python #панды #векторизация

Вопрос:

У меня есть данные, которые выглядят как:

 index stringColumn
0 A_B_B_B_C_C_D
1 A_B_C_D
2 B_C_D_E_F
3 A_E_F_F_F
  

Мне нужно векторизовать этот stringColumn с помощью счетчиков, в итоге:

 index A B C D E F
0 1 3 2 1 0 0
1 1 1 1 1 0 0 
2 0 1 1 1 1 1
3 1 0 0 0 1 3
  

Поэтому мне нужно сделать оба: подсчет и разделение. Функция Pandas str.get_dummies() позволяет мне разделить строку, используя аргумент sep = ‘_’, однако она не учитывает несколько значений. pd.get_dummies() выполняет подсчет, но не допускает разделения.

Мои данные огромны, поэтому я ищу векторизованные решения, а не циклы.

Ответ №1:

Вы можете использовать Series.str.split с get_dummies и sum :

 df1 = (pd.get_dummies(df['stringColumn'].str.split('_', expand=True), 
                    prefix='', prefix_sep='')
         .sum(level=0, axis=1))
  

Или подсчитайте значения по строкам на value_counts , замените пропущенные значения на DataFrame.fillna и преобразуйте в целые числа:

 df1 = (df['stringColumn'].str.split('_', expand=True)
                         .apply(pd.value_counts, axis=1)
                         .fillna(0)  
                         .astype(int))
       
  

Или используйте collections.Counter , производительность должна быть очень хорошей:

 from collections import Counter

df1 = (pd.DataFrame([Counter(x.split('_')) for x in df['stringColumn']])
         .fillna(0)
         .astype(int))
        
  

Или изменить форму по DataFrame.stack и подсчитать по SeriesGroupBy.value_counts :

 df1 = (df['stringColumn'].str.split('_', expand=True)
                         .stack()
                         .groupby(level=0)
                         .value_counts()
                         .unstack(fill_value=0))
  

 print (df1)

   A  B  C  D  E  F
0  1  3  2  1  0  0
1  1  1  1  1  0  0
2  0  1  1  1  1  1
3  1  0  0  0  1  3
  

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

1. Все работает! Спасибо. Я хочу сообщить вам об их времени выполнения для небольшой части моего набора данных, чтобы их сложность была известна: 1-е решение: 15,3 секунды 2-е решение: 1,66 секунды 3-е решение: 44 миллисекунды! 4-е решение: 1.28 сек.