2016-02-06 51 views
1

也許我想的是錯誤的方式,但我想不出一個簡單的方法來做到這一點在熊貓。我試圖獲得一個數據框,該數據框被設置點之上的計數值與下面的計數值之間的關係過濾。它是更爲複雜,它如何比較大熊貓的羣體大小

人爲的例子:比方說,我有人民和他們的考試成績在幾個測試數據集:

 
Person | day | test score | 
---------------------------- 
Bob  1  10 
Bob  2  40 
Bob  3  45 
Mary  1  30 
Mary  2  35 
Mary  3  45 

我想通過考試分數的數量來過濾該數據幀> = 40,但總人數爲每人。假設我將閾值設置爲50%。所以鮑勃會有三分之二的考試成績,但瑪麗會得到三分之一的成績並被排除在外。

我的最終目標是讓一個groupby對象做/ /等。在那些符合門檻的。所以在這種情況下,它看起來像這樣:

 
     test score 
Person | above_count | total | score mean | 
------------------------------------------- 
Bob  2    3  31.67 

我試過以下,但無法弄清楚怎麼做我的groupby對象。

df = pd.read_csv("all_data.csv") 
gb = df.groupby('Person') 
df2 = df[df['test_score'] >= 40] 
gb2 = df2.groupby('Person') 

# This would get me the count for each person but how to compare it? 
gb.size() 

回答

0
import pandas as pd 

df = pd.DataFrame({'Person': ['Bob'] * 3 + ['Mary'] * 4, 
        'day': [1, 2, 3, 1, 2, 3, 4], 
        'test_score': [10, 40, 45, 30, 35, 45, 55]}) 

>>> df 
    Person day test_score 
0 Bob 1   10 
1 Bob 2   40 
2 Bob 3   45 
3 Mary 1   30 
4 Mary 2   35 
5 Mary 3   45 
6 Mary 4   55 

groupby操作中,可以傳遞不同的函數以通過字典在同一列執行操作。

result = df.groupby('Person').test_score.agg(
       {'total': pd.Series.count, 
       'test_score_above_mean': lambda s: s.ge(40).sum(), 
       'score mean': np.mean}) 
>>> result 
     test_score_above_mean total score mean 
Person           
Bob       2  3 31.666667 
Mary      2  4 41.250000 

>>> result[result.test_score_above_mean.gt(result.total * .5)] 
     test_score_above_mean total score mean 
Person           
Bob       2  3 31.666667 
+0

只是好奇,是否有使用.sum()而不是.count()的原因? – user1601333

+0

's.ge(40)'將會產生一個boolean arrary。如果你總結他們,你會得到True實例的數量。如果你計數,你會得到觀察次數(包括假值)。 – Alexander

0

我認爲這可能是有意義的使用GROUPBY和聚合,生成每個列作爲pd.Series,然後在最後一起把它們粘貼。

df = pd.DataFrame([['Bob',1,10],['Bob',2,40],['Bob',3,45], 
['Mary',1,30],['Mary',2,35],['Mary',3,45]], columns= 
['Person','day', 'test score']) 
df_group = df.groupby('Person') 
above_count = df_group.apply(lambda x: x[x['test score'] >= 40]['test score'].count()) 
above_count.name = 'test score above_count' 
total_count = df_group['test score'].agg(np.size) 
total_count.name = 'total' 
test_mean = df_group['test score'].agg(np.mean) 
test_mean.name = 'score mean' 
results = pd.concat([above_count, total_count, test_mean]) 
0

點心和平均可以.agg()做一個GROUPBY對象,但是你做一個flexible apply閾值函數的力量。

未經檢驗的,但這樣的事情應該工作:

df.groupby('Person').apply(lambda x: sum(x > 40), sum(x), mean(x)) 

你可以做的lambda函數實現你想要的所有條件/功能的更復雜,常規功能。

+0

我喜歡這種方法的簡潔,但我無法想出一種方法來構造函數來獲得我期待的結果。 – user1601333

0

有這樣做的一個簡單的方法...

import pandas as pd 
import numpy as np 

data = '''Bob  1  10 
Bob  2  40 
Bob  3  45 
Mary  1  30 
Mary  2  35 
Mary  3  45''' 

data = [d.split() for d in data.split('\n')] 
data = pd.DataFrame(data, columns=['Name', 'day', 'score']) 
data.score = data.score.astype(float) 
data['pass'] = (data.score >=40)*1 
data['total'] = 1 

您添加兩列,方便計算數據。結果應該是這樣的......

Name day score pass total 
0 Bob 1  10  0  1 
1 Bob 2  40  1  1 
2 Bob 3  45  1  1 
3 Mary 1  30  0  1 
4 Mary 2  35  0  1 
5 Mary 3  45  1  1 

現在您彙總數據......

summary = data.groupby('Name').agg(np.sum).reset_index() 
summary['mean score'] = summary['score']/summary['total'] 
summary['pass ratio'] = summary['pass']/summary['total'] 
print summary 

結果看起來像這樣...

Name score pass total mean score pass ratio 
0 Bob  95  2  3 31.666667 0.666667 
1 Mary 110  1  3 36.666667 0.333333 

現在,你可以總是根據通過率篩選出名稱...