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