2016-03-28 47 views
6

Tôi có một dataframe pandas với một số hàng gần trùng lặp nhau, ngoại trừ một giá trị. Mục tiêu của tôi là hợp nhất hoặc "hợp nhất" các hàng này thành một hàng duy nhất, mà không tính tổng các giá trị bằng số.gấu trúc - Hợp nhất các hàng gần giống nhau dựa trên giá trị cột

Dưới đây là một ví dụ về những gì tôi đang làm việc với:

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 

Và đây là những gì tôi muốn:

Name Sid Use_Case   Revenue 
A  xx01 Voice, SMS   $10.00 
B  xx02 Voice    $5.00 
C  xx03 Voice, SMS, Video $15.00 

Lý do tôi không muốn tính tổng "Doanh thu "là vì bảng của tôi là kết quả của việc thực hiện xoay vòng trong một số khoảng thời gian mà" Doanh thu "chỉ đơn giản là kết thúc việc liệt kê nhiều lần thay vì có giá trị khác cho mỗi" Use_Case ".

Cách tốt nhất để giải quyết vấn đề này là gì? Tôi đã xem xét chức năng groupby() nhưng tôi vẫn không hiểu nó rất tốt.

+0

Nếu câu trả lời của tôi hoặc Ami là hữu ích, đừng quên [chấp nhận] (http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) nó. Cảm ơn. – jezrael

+0

Cảm ơn bạn! Cả hai đều hoạt động tốt. Tôi có thể phải hợp nhất một vài cột như tập dữ liệu thực tế của tôi là rộng hơn nhiều so với 4 tôi cung cấp, nhưng điều đó nên làm các trick –

Trả lời

5

Tôi nghĩ rằng bạn có thể sử dụng groupby với aggregatefirst và chức năng tùy chỉnh ', '.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 

Ý tưởng tốt đẹp từ bình luận, nhờ Goyo:

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 
+1

Tôi sẽ nhóm bởi tất cả mọi thứ ngoại trừ ''Use_Case'', chỉ trong trường hợp. Ngoài ra, hàm tổng hợp có thể chỉ là '',' .join', không cần sử dụng' lambda' .. – Goyo

+0

Tắt các ngắt này nếu cột của bạn có các giá trị 'join' không thích. Tôi đã phải ném một '.map (str)' vào trước 'apply' để nó hoạt động một cách rõ ràng. –

+1

Có, hoặc sử dụng '.astype (str)', nó là hàm để truyền thành chuỗi. – jezrael

1

Bạn có thể groupbyapply các list chức năng:

>>> 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] 

(Trong trường hợp bạn đang lo ngại về bản sao, sử dụng set thay vì list.)

1

Tôi đã sử dụng một số mã mà tôi không nghĩ là tối ưu và cuối cùng tìm thấy jezrael's answer. Nhưng sau khi sử dụng nó và chạy một thử nghiệm timeit, tôi thực sự quay trở lại với những gì tôi đang làm, đó là:

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()] 

Theo thử nghiệm 100 chạy timeit tôi, lặp và thay thế phương pháp là một thứ tự cường độ nhanh hơn phương pháp 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())) 

sản lượng:

Interim Dict 
    Total: 59.1164s 
    Avg: 591163748.5887ns 

Group By 
    Total: 430.6203s 
    Avg: 4306203366.1827ns 

nơi time_something là một chức năng mà lần một đoạn với timeit và trả kết quả theo định dạng trên.

Các vấn đề liên quan