Использование:
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())
Объяснение :
- Установить
Count
для индексации по set_index
для предотвращения потериэта информация - Создать
DataFrame
с помощью split
- Изменить на
stack
- Преобразовать
MultiIndex
встолбцы по reset_index
- Совокупность
sum
- сортировка
Series
по Series.sort_values
- Последняя
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
Объяснение :
- Первое повторение
Count
значений с разбитыми значениями Keyword
на новый DataFrame - Агрегирование
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)