2013-03-13 107 views
18

我有一个名为my_labels的包含字符串的列的熊猫数据框:'A', 'B', 'C', 'D', 'E'。我想要计算每个字符串的出现次数,然后将计数次数除以所有计数的总和。我试图做到这一点在熊猫这样的:将函数应用到pandas groupby

func = lambda x: x.size()/x.sum() 
data = frame.groupby('my_labels').apply(func) 

此代码抛出一个错误,“数据帧对象有没有属性‘大小’。我怎样才能应用一个函数来计算熊猫呢?

回答

21

apply具有适用于各个值的功能,而不是系列,并接受kwargs。 所以,这些值没有.size()方法。

也许这会工作:

from pandas import * 

d = {"my_label": Series(['A','B','A','C','D','D','E'])} 
df = DataFrame(d) 


def as_perc(value, total): 
    return value/float(total) 

def get_count(values): 
    return len(values) 

grouped_count = df.groupby("my_label").my_label.agg(get_count) 
data = grouped_count.apply(as_perc, total=df.my_label.count()) 

.agg()方法这里需要被应用到groupby object的所有值的功能。

6

尝试:

g = pd.DataFrame(['A','B','A','C','D','D','E']) 

# Group by the contents of column 0 
gg = g.groupby(0) 

# Create a DataFrame with the counts of each letter 
histo = gg.apply(lambda x: x.count()) 

# Add a new column that is the count/total number of elements  
histo[1] = histo.astype(np.float)/len(g) 

print histo 

输出:

0   1 
0    
A 2 0.285714 
B 1 0.142857 
C 1 0.142857 
D 2 0.285714 
E 1 0.142857 
+1

你也可以使用'HISTO = gg.size()'为简单起见相当快 – Reservedegotist 2013-03-13 01:13:51

1

只见嵌套函数技术,用于计算上S.O.加权平均有一次,改变这种技术可以解决你的问题。

def group_weight(overall_size): 
    def inner(group): 
     return len(group)/float(overall_size) 
    inner.__name__ = 'weight' 
    return inner 

d = {"my_label": pd.Series(['A','B','A','C','D','D','E'])} 
df = pd.DataFrame(d) 
print df.groupby('my_label').apply(group_weight(len(df))) 



my_label 
A 0.285714 
B 0.142857 
C 0.142857 
D 0.285714 
E 0.142857 
dtype: float64 

这里是如何做到组内的加权平均

def wavg(val_col_name,wt_col_name): 
    def inner(group): 
     return (group[val_col_name] * group[wt_col_name]).sum()/group[wt_col_name].sum() 
    inner.__name__ = 'wgt_avg' 
    return inner 



d = {"P": pd.Series(['A','B','A','C','D','D','E']) 
    ,"Q": pd.Series([1,2,3,4,5,6,7]) 
    ,"R": pd.Series([0.1,0.2,0.3,0.4,0.5,0.6,0.7]) 
    } 

df = pd.DataFrame(d) 
print df.groupby('P').apply(wavg('Q','R')) 

P 
A 2.500000 
B 2.000000 
C 4.000000 
D 5.545455 
E 7.000000 
dtype: float64 
0

Starting with Pandas version 0.22,也存在于apply替代:pipe,这可以大大快于使用apply(你也可以检查this question以获得两种功能之间的更多差异)。

对于示例:

df = pd.DataFrame({"my_label": ['A','B','A','C','D','D','E']}) 

    my_label 
0  A 
1  B 
2  A 
3  C 
4  D 
5  D 
6  E 

apply版本

df.groupby('my_label').apply(lambda grp: grp.count()/df.shape[0]) 

  my_label 
my_label   
A   0.285714 
B   0.142857 
C   0.142857 
D   0.285714 
E   0.142857 

pipe版本

df.groupby('my_label').pipe(lambda grp: grp.size()/grp.size().sum()) 

产生

my_label 
A 0.285714 
B 0.142857 
C 0.142857 
D 0.285714 
E 0.142857 

所以值是相同的,然而,定时相差相当多(至少对于这个小数据帧):

%timeit df.groupby('my_label').apply(lambda grp: grp.count()/df.shape[0]) 
100 loops, best of 3: 5.52 ms per loop 

%timeit df.groupby('my_label').pipe(lambda grp: grp.size()/grp.size().sum()) 
1000 loops, best of 3: 843 µs per loop 

将它包装成功能也很简单:

def get_perc(grp_obj): 
    gr_size = grp_obj.size() 
    return gr_size/gr_size.sum() 

现在,您可以拨打

df.groupby('my_label').pipe(get_perc) 

产生

my_label 
A 0.285714 
B 0.142857 
C 0.142857 
D 0.285714 
E 0.142857 

然而,对于这种特殊情况下,你甚至不需要一个groupby,但你可以只使用value_counts这样的:

df['my_label'].value_counts(sort=False)/df.shape[0] 

收益率

A 0.285714 
C 0.142857 
B 0.142857 
E 0.142857 
D 0.285714 
Name: my_label, dtype: float64 

对于这个小数据帧是

%timeit df['my_label'].value_counts(sort=False)/df.shape[0] 
1000 loops, best of 3: 770 µs per loop