2017-12-21 152 views
7

Trong Python Pandas, tôi có một DataFrame. Tôi nhóm DataFrame này theo một cột và muốn gán giá trị cuối cùng của một cột cho tất cả các hàng của một cột khác.Python Pandas: Gán giá trị cuối cùng của nhóm DataFrame cho tất cả các mục của nhóm đó

Tôi biết rằng tôi có thể chọn hàng cuối cùng của nhóm bằng lệnh này:

import pandas as pd 

df = pd.DataFrame({'a': (1,1,2,3,3), 'b':(20,21,30,40,41)}) 
print(df) 
print("-") 
result = df.groupby('a').nth(-1) 
print(result) 

Kết quả:

a b 
0 1 20 
1 1 21 
2 2 30 
3 3 40 
4 3 41 
- 
    b 
a  
1 21 
2 30 
3 41 

Làm thế nào nó sẽ có thể gán kết quả của hoạt động này quay lại dataframe ban đầu để tôi có một cái gì đó như:

a b b_new 
0 1 20 21 
1 1 21 21 
2 2 30 30 
3 3 40 41 
4 3 41 41 

Trả lời

4

Sử dụng transform với last:

df['b_new'] = df.groupby('a')['b'].transform('last') 

Alternative:

df['b_new'] = df.groupby('a')['b'].transform(lambda x: x.iat[-1]) 

print(df) 
    a b b_new 
0 1 20  21 
1 1 21  21 
2 2 30  30 
3 3 40  41 
4 3 41  41 

Giải pháp với nthjoin:

df = df.join(df.groupby('a')['b'].nth(-1).rename('b_new'), 'a') 
print(df) 
    a b b_new 
0 1 20  21 
1 1 21  21 
2 2 30  30 
3 3 40  41 
4 3 41  41 

Thời gian:

N = 10000 

df = pd.DataFrame({'a':np.random.randint(1000,size=N), 
        'b':np.random.randint(10000,size=N)}) 

#print (df) 


def f(df): 
    return df.join(df.groupby('a')['b'].nth(-1).rename('b_new'), 'a') 

#cᴏʟᴅsᴘᴇᴇᴅ1 
In [211]: %timeit df['b_new'] = df.a.map(df.groupby('a').b.nth(-1)) 
100 loops, best of 3: 3.57 ms per loop 

#cᴏʟᴅsᴘᴇᴇᴅ2 
In [212]: %timeit df['b_new'] = df.a.replace(df.groupby('a').b.nth(-1)) 
10 loops, best of 3: 71.3 ms per loop 

#jezrael1 
In [213]: %timeit df['b_new'] = df.groupby('a')['b'].transform('last') 
1000 loops, best of 3: 1.82 ms per loop 

#jezrael2 
In [214]: %timeit df['b_new'] = df.groupby('a')['b'].transform(lambda x: x.iat[-1]) 
10 loops, best of 3: 178 ms per loop 

#jezrael3 
In [219]: %timeit f(df) 
100 loops, best of 3: 3.63 ms per loop 

Caveat

Các kết quả này không giải quyết vấn đề hiệu suất cho số lượng các nhóm, mà sẽ ảnh hưởng đến timings rất nhiều đối với một số các giải pháp này.

6

Hai khả năng, với groupby + nth + map hoặc replace

df['b_new'] = df.a.map(df.groupby('a').b.nth(-1)) 

Hoặc,

df['b_new'] = df.a.replace(df.groupby('a').b.nth(-1)) 

Bạn cũng có thể thay thế nth(-1) với last() (trong thực tế, làm như vậy sẽ xảy ra để làm điều này một chút nhanh hơn), nhưng nth mang lại cho bạn sự linh hoạt hơn so với mục nào để chọn từ mỗi nhóm trong b.


df 

    a b b_new 
0 1 20  21 
1 1 21  21 
2 2 30  30 
3 3 40  41 
4 3 41  41 
2

Tôi nghĩ rằng điều này sẽ được nhanh chóng

df.merge(df.drop_duplicates('a',keep='last'),on='a',how='left') 
Out[797]: 
    a b_x b_y 
0 1 20 21 
1 1 21 21 
2 2 30 30 
3 3 40 41 
4 3 41 41 
Các vấn đề liên quan