Pandas - объединить почти повторяющиеся строки на основе значения столбца
У меня есть pandas
dataframe с несколькими строками, которые находятся рядом с дубликатами друг друга, за исключением одного значения. Моя цель - объединить или "объединить" эти строки в одну строку, не суммируя числовые значения.
Вот пример того, с чем я работаю:
Name Sid Use_Case Revenue
A xx01 Voice $10.00
A xx01 SMS $10.00
B xx02 Voice $5.00
C xx03 Voice $15.00
C xx03 SMS $15.00
C xx03 Video $15.00
И вот что мне хотелось бы:
Name Sid Use_Case Revenue
A xx01 Voice, SMS $10.00
B xx02 Voice $5.00
C xx03 Voice, SMS, Video $15.00
Причина, по которой я не хочу суммировать столбец "Доход", заключается в том, что моя таблица является результатом поворота в течение нескольких периодов времени, когда "Доход" просто заканчивается тем, что перечисляется несколько раз вместо того, чтобы иметь другое значение за "Use_Case".
Каким будет лучший способ решить эту проблему? Я просмотрел функцию groupby()
, но я все еще не очень хорошо ее понимаю.
Ответы
Ответ 1
Я думаю, что вы можете использовать groupby
с aggregate
first
и пользовательской функцией ', '.join
:
df = df.groupby('Name').agg({'Sid':'first',
'Use_Case': ', '.join,
'Revenue':'first' }).reset_index()
#change column order
print df[['Name','Sid','Use_Case','Revenue']]
Name Sid Use_Case Revenue
0 A xx01 Voice, SMS $10.00
1 B xx02 Voice $5.00
2 C xx03 Voice, SMS, Video $15.00
Хорошая идея из комментария, спасибо Гойо:
df = df.groupby(['Name','Sid','Revenue'])['Use_Case'].apply(', '.join).reset_index()
#change column order
print df[['Name','Sid','Use_Case','Revenue']]
Name Sid Use_Case Revenue
0 A xx01 Voice, SMS $10.00
1 B xx02 Voice $5.00
2 C xx03 Voice, SMS, Video $15.00
Ответ 2
Я использовал какой-то код, который я не считал оптимальным, и в итоге нашел jezrael answer. Но после использования и запуска теста timeit
я действительно вернулся к тому, что делал, а именно:
cmnts = {}
for i, row in df.iterrows():
while True:
try:
if row['Use_Case']:
cmnts[row['Name']].append(row['Use_Case'])
else:
cmnts[row['Name']].append('n/a')
break
except KeyError:
cmnts[row['Name']] = []
df.drop_duplicates('Name', inplace=True)
df['Use_Case'] = ['; '.join(v) for v in cmnts.values()]
В соответствии с моим тестом 100 t timeit
метод итерации и замены на порядок быстрее, чем метод groupby
.
import pandas as pd
from my_stuff import time_something
df = pd.DataFrame({'a': [i / (i % 4 + 1) for i in range(1, 10001)],
'b': [i for i in range(1, 10001)]})
runs = 100
interim_dict = 'txt = {}\n' \
'for i, row in df.iterrows():\n' \
' try:\n' \
" txt[row['a']].append(row['b'])\n\n" \
' except KeyError:\n' \
" txt[row['a']] = []\n" \
"df.drop_duplicates('a', inplace=True)\n" \
"df['b'] = ['; '.join(v) for v in txt.values()]"
grouping = "new_df = df.groupby('a')['b'].apply(str).apply('; '.join).reset_index()"
print(time_something(interim_dict, runs, beg_string='Interim Dict', glbls=globals()))
print(time_something(grouping, runs, beg_string='Group By', glbls=globals()))
дает:
Interim Dict
Total: 59.1164s
Avg: 591163748.5887ns
Group By
Total: 430.6203s
Avg: 4306203366.1827ns
где time_something
- это функция, которая умножает фрагмент с timeit
и возвращает результат в указанном выше формате.
Ответ 3
Вы можете groupby
и apply
использовать функцию list
:
>>> df['Use_Case'].groupby([df.Name, df.Sid, df.Revenue]).apply(list).reset_index()
Name Sid Revenue 0
0 A xx01 $10.00 [Voice, SMS]
1 B xx02 $5.00 [Voice]
2 C xx03 $15.00 [Voice, SMS, Video]
(Если вас беспокоят дубликаты, используйте set
вместо list
.)
Ответ 4
последующий запрос: я новичок в pandas и мне нужно выполнить объединение похожих строк, однако в моем случае у меня более одного столбца, который не похож и требует объединения
Мне очень понравилось решение Гойо, есть ли подобное решение для моего случая?
Ответ 5
Как я могу присоединиться к столбцу use_case в форме словаря? То есть я хочу результат в виде
Name Sid Use_Case Revenue
A xx01 {Voice:1, SMS:1} $10.00
B xx02 {Voice:1} $5.00
C xx03 {Voice:1, SMS:1, Video:1} $15.00