2013-03-23 14 views
11

Vấn đề của tôi là cách tính tần số trên nhiều biến trong gấu trúc. Tôi có từ dataframe này:Bảng tần số trong gấu trúc (như plyr trong R)

d1 = pd.DataFrame({'StudentID': ["x1", "x10", "x2","x3", "x4", "x5", "x6", "x7",  "x8", "x9"], 
         'StudentGender' : ['F', 'M', 'F', 'M', 'F', 'M', 'F', 'M', 'M', 'M'], 
       'ExamenYear': ['2007','2007','2007','2008','2008','2008','2008','2009','2009','2009'], 
       'Exam': ['algebra', 'stats', 'bio', 'algebra', 'algebra', 'stats', 'stats', 'algebra', 'bio', 'bio'], 
       'Participated': ['no','yes','yes','yes','no','yes','yes','yes','yes','yes'], 
        'Passed': ['no','yes','yes','yes','no','yes','yes','yes','no','yes']}, 
        columns = ['StudentID', 'StudentGender', 'ExamenYear', 'Exam', 'Participated', 'Passed']) 

Để kết quả sau

   Participated OfWhichpassed 
ExamenYear        
2007     3    2 
2008     4    3 
2009     3    2 

(1) Một khả năng tôi đã cố gắng là để tính toán hai dataframe và ràng buộc họ

t1 = d1.pivot_table(values = 'StudentID', rows=['ExamenYear'], cols = ['Participated'], aggfunc = len) 
t2 = d1.pivot_table(values = 'StudentID', rows=['ExamenYear'], cols = ['Passed'], aggfunc = len) 
tx = pd.concat([t1, t2] , axis = 1) 

Res1 = tx['yes'] 

(2) Khả năng thứ hai là sử dụng một hàm tổng hợp.

import collections 
dg = d1.groupby('ExamenYear') 
Res2 = dg.agg({'Participated': len,'Passed': lambda x : collections.Counter(x == 'yes')[True]}) 

Res2.columns = ['Participated', 'OfWhichpassed'] 

Cả hai cách rất khó để nói điều ít nhất. Cách này được thực hiện đúng cách trong gấu trúc?

PS: Tôi cũng đã cố gắng value_counts thay vì collections.Counter nhưng không thể làm cho nó làm việc

Để tham khảo: Vài tháng trước, tôi hỏi câu hỏi tương tự cho R hereplyr thể giúp

---- CẬP NHẬT ------

dùng DSM là đúng. đã xảy ra lỗi trong kết quả bảng mong muốn.

(1) Các mã cho lựa chọn một là

t1 = d1.pivot_table(values = 'StudentID', rows=['ExamenYear'], aggfunc = len) 
t2 = d1.pivot_table(values = 'StudentID', rows=['ExamenYear'], cols = ['Participated'], aggfunc = len) 
t3 = d1.pivot_table(values = 'StudentID', rows=['ExamenYear'], cols = ['Passed'], aggfunc = len) 

Res1 = pd.DataFrame({'All': t1, 
         'OfWhichParticipated': t2['yes'], 
        'OfWhichPassed': t3['yes']}) 

Nó sẽ tạo ra kết quả

   All OfWhichParticipated OfWhichPassed 
ExamenYear           
2007   3     2    2 
2008   4     3    3 
2009   3     3    2 

(2) Đối với Lựa chọn 2, nhờ sử dụng herrfz, tôi đã tìm ra cách để sử dụng value_count và mã sẽ là

Res2 = d1.groupby('ExamenYear').agg({'StudentID': len, 
           'Participated': lambda x: x.value_counts()['yes'], 
           'Passed': lambda x: x.value_counts()['yes']}) 

Res2.columns = ['All', 'OfWgichParticipated', 'OfWhichPassed'] 

sẽ tạo thứ e cùng kết quả như Res1

Câu hỏi của tôi vẫn còn mặc dù: (? cho các hoạt động khác)

Sử dụng Lựa chọn 2, nó sẽ có thể sử dụng các biến tương tự hai lần người ta có thể vượt qua một tên tùy chỉnh cho biến kết quả?

---- Một CẬP NHẬT MỚI ----

tôi cuối cùng đã quyết định sử dụng áp dụng mà tôi hiểu là linh hoạt hơn.

+0

Tôi không chắc tôi hiểu đầu ra của bạn. Nhìn vào năm 2007, dường như có hai sinh viên đã tham gia = có, nhưng kết quả mong muốn của bạn có "3" - tức là tất cả sinh viên năm 2007. Vì vậy, bạn có muốn các giá trị của cột Tham gia mới được tính không? – DSM

+0

.. thực sự, 'Res1' và' Res2' của bạn không đồng ý về điều này, vì vậy tôi không chắc bạn đã quyết định hay chưa. – DSM

+0

bạn đúng: ý tôi là với 'Tham gia' thực sự là chiều dài của DataFrame (và không tham gia == có). Không sao, tôi nghĩ giải pháp thứ hai có vẻ hứa hẹn hơn – user1043144

Trả lời

7

này:

d1.groupby('ExamenYear').agg({'Participated': len, 
           'Passed': lambda x: sum(x == 'yes')}) 

không giống cách vụng về hơn so với giải pháp R, IMHO.

+0

Cảm ơn. Đây là một sự cải tiến. Có khả năng chuyển tên tùy chỉnh cho cột kết quả không (ví dụ: OfWhichpassed). Rõ ràng bạn có thể vượt qua một tuple tên tùy chỉnh để agg ('customname', 'nameoffunction') nhưng nó có hoạt động ở đây không? – user1043144

11

Cuối cùng tôi đã quyết định sử dụng áp dụng.

Tôi đăng những gì tôi nghĩ ra với hy vọng rằng nó có thể hữu ích cho người khác.

Từ những gì tôi hiểu từ cuốn sách Wes' Python để phân tích dữ liệu "

  • áp dụng là linh hoạt hơn agg và biến đổi vì bạn có thể xác định chức năng của riêng bạn.
  • yêu cầu duy nhất là các hàm trả về đối tượng gấu trúc hoặc giá trị vô hướng.
  • các cơ chế nội tại: hàm được gọi trên mỗi mảnh của đối tượng được nhóm lại kết quả abd được dán lại với nhau sử dụng pandas.concat
  • Một cần phải "cứng-mã" cấu trúc bạn muốn hiển thị ở cuối

Dưới đây là những gì tôi đã đưa ra

def ZahlOccurence_0(x): 
     return pd.Series({'All': len(x['StudentID']), 
         'Part': sum(x['Participated'] == 'yes'), 
         'Pass' : sum(x['Passed'] == 'yes')}) 

khi tôi chạy nó:

d1.groupby('ExamenYear').apply(ZahlOccurence_0) 

tôi nhận được kết quả chính xác

  All Part Pass 
ExamenYear     
2007   3  2  2 
2008   4  3  3 
2009   3  3  2 

Cách tiếp cận này cũng sẽ cho phép tôi kết hợp tần số với số liệu thống kê khác

import numpy as np 
d1['testValue'] = np.random.randn(len(d1)) 

def ZahlOccurence_1(x): 
    return pd.Series({'All': len(x['StudentID']), 
     'Part': sum(x['Participated'] == 'yes'), 
     'Pass' : sum(x['Passed'] == 'yes'), 
     'test' : x['testValue'].mean()}) 


d1.groupby('ExamenYear').apply(ZahlOccurence_1) 


      All Part Pass  test 
ExamenYear       
2007   3  2  2 0.358702 
2008   4  3  3 1.004504 
2009   3  3  2 0.521511 

Tôi hy vọng ai đó sẽ tìm thấy hữu ích

1

này có cách tiếp cận khác mà tôi muốn sử dụng cho các sự cố tương tự, nó sử dụng groupbyunstack:

d1 = pd.DataFrame({'StudentID': ["x1", "x10", "x2","x3", "x4", "x5", "x6", "x7",  "x8", "x9"], 
        'StudentGender' : ['F', 'M', 'F', 'M', 'F', 'M', 'F', 'M', 'M', 'M'], 
        'ExamenYear': ['2007','2007','2007','2008','2008','2008','2008','2009','2009','2009'], 
        'Exam': ['algebra', 'stats', 'bio', 'algebra', 'algebra', 'stats', 'stats', 'algebra', 'bio', 'bio'], 
        'Participated': ['no','yes','yes','yes','no','yes','yes','yes','yes','yes'], 
        'Passed': ['no','yes','yes','yes','no','yes','yes','yes','no','yes']}, 
        columns = ['StudentID', 'StudentGender', 'ExamenYear', 'Exam', 'Participated', 'Passed']) 

(điều này chỉ là dữ liệu thô từ trên cao)

d2 = d1.groupby("ExamenYear").Participated.value_counts().unstack(fill_value=0)['yes'] 
d3 = d1.groupby("ExamenYear").Passed.value_counts().unstack(fill_value=0)['yes'] 
d2.name = "Participated" 
d3.name = "Passed" 

pd.DataFrame(data=[d2,d3]).T 
      Participated Passed 
ExamenYear      
2007     2  2 
2008     3  3 
2009     3  2 

Giải pháp này là hơi nhiều cồng kềnh so với cái trên sử dụng được áp dụng, nhưng điều này là dễ hiểu và mở rộng, tôi cảm thấy.

6

Bạn có thể sử dụng chức năng pandas crosstab, theo mặc định tính bảng tần số của hai hoặc nhiều biến. Ví dụ:

> import pandas as pd 
> pd.crosstab(d1['ExamenYear'], d1['Passed']) 
Passed  no yes 
ExamenYear   
2007   1 2 
2008   1 3 
2009   1 2 

tùy chọn sử dụng tùy chọn margins=True nếu bạn cũng muốn xem tổng phụ của mỗi hàng và cột.

> pd.crosstab(d1['ExamenYear'], d1['Participated'], margins=True) 
Participated no yes All 
ExamenYear     
2007   1 2 3 
2008   1 3 4 
2009   0 3 3 
All   2 8 10