Как мне сделать взвешенное количество слов из сводной таблицы - PullRequest
0 голосов
/ 29 января 2019

Вот моя сводная таблица

No  Keyword              Count
1   Sell Laptop Online   10
2   Buy Computer Online  8
3   Laptop and Case      5

Вот что я хочу

No   Word      Count
1    Online    18
2    Laptop    15
3    Sell      10
4    Buy        8
5    Computer   8
6    and        5
7    Case       5 

То, что я сделал, это

df['Word'].apply(lambda x: x.str.split(expand=True).stack()).stack().value_counts()

Но результат равен

No   Word      Count
1    Online    2
2    Laptop    2
3    Sell      1
4    Buy       1
5    Computer  1
6    and       1
7    Case      1 

Я хочу взвешенное количество слов из сводной таблицы

Ответы [ 2 ]

0 голосов
/ 29 января 2019

Вот простой метод с одним горячим кодированием.

df['Keyword'].str.get_dummies(sep=' ').mul(df['Count'],axis=0).sum(0).to_frame('Count')

          Count
Buy           8
Case          5
Computer      8
Laptop       15
Online       18
Sell         10
and           5

В случае повышения скорости, попробуйте мультинаборный бинаризатор от Scikit.т. е.

from sklearn.preprocessing import MultiLabelBinarizer
vec = MultiLabelBinarizer()

oh = (vec.fit_transform(df['Keyword'].str.split()) * df['Count'].values[:,None]).sum(0)
pd.DataFrame({'Count': oh ,'Word':vec.classes_})

Объяснение :

Получение пустышек приведет к горячему горячему кодированию кадра данных,

    Buy  Case  Computer  Laptop  Online  Sell  and
 0    0     0         0       1       1     1    0
 1    1     0         1       0       1     0    0
 2    0     1         0       1       0     0    1

Умножьте на число черезстолбцы

   Buy  Case  Computer  Laptop  Online  Sell  and
0    0     0         0      10      10    10    0
1    8     0         8       0       8     0    0
2    0     5         0       5       0     0    5

Суммируйте их и преобразуйте в формат данных.

Buy          8
Case         5
Computer     8
Laptop      15
Online      18
Sell        10
and          5
dtype: int64
0 голосов
/ 29 января 2019

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

df1 = (df.set_index('Count')['Keyword']
         .str.split(expand=True)
         .stack()
         .reset_index(name='Word')
         .groupby('Word')['Count']
         .sum()
         .sort_values(ascending=False)
         .reset_index())

Объяснение :

  1. Установить Count для индексации по set_index для предотвращения потериэта информация
  2. Создать DataFrame с помощью split
  3. Изменить на stack
  4. Преобразовать MultiIndex встолбцы по reset_index
  5. Совокупность sum
  6. сортировка Series по Series.sort_values
  7. Последняя reset_index

Другое решение - быстрее, если больше DataFrame:

from itertools import chain

s = df['Keyword'].str.split()

df = pd.DataFrame({
    'Word' : list(chain.from_iterable(s.values.tolist())), 
    'Count' : df['Count'].repeat(s.str.len())
})

print (df)
       Word  Count
0      Sell     10
0    Laptop     10
0    Online     10
1       Buy      8
1  Computer      8
1    Online      8
2    Laptop      5
2       and      5
2      Case      5

df1 = df.groupby('Word')['Count'].sum().sort_values(ascending=False).reset_index()
print (df1)
       Word  Count
0    Online     18
1    Laptop     15
2      Sell     10
3  Computer      8
4       Buy      8
5       and      5
6      Case      5

Объяснение :

  1. Первое повторение Count значений с разбитыми значениями Keyword на новый DataFrame
  2. Агрегирование sum, сортировка по серии и последнему reset_index

Решение с defaultdict:

from collections import defaultdict

out = defaultdict(int)
for k, c in zip(df['Keyword'], df['Count']):
    for x in k.split():
        out[x] += c

print (out)
defaultdict(<class 'int'>, {'Sell': 10,
                            'Laptop': 15, 
                            'Online': 18, 
                            'Buy': 8, 
                            'Computer': 8,
                            'and': 5,
                            'Case': 5})

#sorting by values and DataFrame constructor
#https://stackoverflow.com/a/613218
df = pd.DataFrame(sorted(out.items(), key=lambda kv: kv[1], reverse=True),
                  columns=['Word','Count'])
print (df)

       Word  Count
0    Online     18
1    Laptop     15
2      Sell     10
3       Buy      8
4  Computer      8
5       and      5
6      Case      5

Производительность - зависит от реальных данных, но кажется, что решение с defaultdict самое быстрое:

np.random.seed(456)

import string
from itertools import chain
from collections import defaultdict


a = np.random.randint(0, 20, 10000)
b = [' '.join(np.random.choice(list(string.ascii_letters), 
                               np.random.randint(3, 5))) for _ in range(len(a))]

df = pd.DataFrame({"Keyword":b, "Count":a})
#print (df)

In [49]: %%timeit
    ...: f1 = (df.set_index('Count')['Keyword']
    ...:          .str.split(expand=True)
    ...:          .stack()
    ...:          .reset_index(name='Word')
    ...:          .groupby('Word')['Count']
    ...:          .sum()
    ...:          .sort_values(ascending=False)
    ...:          .reset_index())
    ...: 
35.5 ms ± 1.88 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [52]: %%timeit
    ...: from itertools import chain
    ...: 
    ...: s = df['Keyword'].str.split()
    ...: 
    ...: pd.DataFrame({
    ...:     'Word' : list(chain.from_iterable(s.values.tolist())), 
    ...:     'Count' : df['Count'].repeat(s.str.len())
    ...: }).groupby('Word')['Count'].sum().sort_values(ascending=False).reset_index()
    ...: 
14.5 ms ± 194 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [53]: %%timeit
    ...: from collections import defaultdict
    ...: 
    ...: out = defaultdict(int)
    ...: for k, c in zip(df['Keyword'], df['Count']):
    ...:     for x in k.split():
    ...:         out[x] += c
    ...: pd.DataFrame(sorted(out.items(), key=lambda kv: kv[1], reverse=True), columns=['Word','Count'])
    ...: 
8.82 ms ± 25.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

#Dark solution
In [54]: %%timeit
    ...: df['Keyword'].str.get_dummies(sep=' ').mul(df['Count'],0).sum(0).to_frame('Count')
    ...: 
307 ms ± 12.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...