您的位置:首页 > 编程语言 > Python开发

利用Python进行数据分析--数据聚合与分组运算

2014-11-18 23:44 881 查看
转载自:http://blog.csdn.net/ssw_1990/article/details/22422971

1、quantile计算Series或DataFrame列的样本分位数:

[python] view
plaincopy





>>> import numpy as np

>>> import pandas as pd

>>> df = pd.DataFrame({'key1':['a', 'a', 'b', 'b', 'a'],

... 'key2':['one', 'two', 'one', 'two', 'one'],

... 'data1':np.random.randn(5),

... 'data2':np.random.randn(5)})

>>> df

data1 data2 key1 key2

0 0.228507 -1.820634 a one

1 -1.253050 0.285551 a two

2 1.412322 1.985010 b one

3 1.080160 -0.125354 b two

4 0.077132 -1.168355 a one

>>> grouped = df.groupby('key1')

>>> grouped

<pandas.core.groupby.DataFrameGroupBy object at 0x03EB3510>

>>> grouped['data1']

<pandas.core.groupby.SeriesGroupBy object at 0x03EB3490>

>>> grouped['data1'].quantile(0.9)

key1

a 0.198232

b 1.379106

dtype: float64

说明:

(1)虽然quantile并没有明确地实现于GroupBy,但它是一个Series方法,所以这里是能用的。实际上,GroupBy会高效地对Series进行切片,然后对各片调用piece.quantile(0.9),最后将这些结果组装成最终结果。

(2)如果传入的百分位上没有值,则quantile会进行线性插值。

(3)四分位数(Quartile),即统计学中,把所有数值由小到大排列并分成四等份,处于三个分割点位置的得分就是四分位数。

(4)线性插值经常用于补充表格中的间隔部分。假设一个表格列出了一个国家 1970年、1980年、1990年以及 2000年的人口,那么如果需要估计 1994年的人口的话,线性插值就是一种简便的方法。

2、有些方法(如describe)也是可以用在这里的,即时严格来讲,它们并非聚合运算:

[python] view
plaincopy





>>> grouped.describe()

data1 data2

key1

a count 3.000000 3.000000

mean -0.315804 -0.901146

std 0.815200 1.078218

min -1.253050 -1.820634

25% -0.587959 -1.494495

50% 0.077132 -1.168355

75% 0.152819 -0.441402

max 0.228507 0.285551

b count 2.000000 2.000000

mean 1.246241 0.929828

std 0.234874 1.492253

min 1.080160 -0.125354

25% 1.163201 0.402237

50% 1.246241 0.929828

75% 1.329282 1.457419

max 1.412322 1.985010

经过优化的groupby的方法

函数名

说明

count

分组中非NA值的数量

sum

非NA值的和

mean

非NA值的平均数

median

非NA值的算术中位数

std、var

无偏(分母为n-1)标准差和方差

min、max

非NA值的最小值和最大值

prod

非NA值的积

first、last

第一个和最后一个非NA值
3、面向列的多函数应用

对Series或DataFrame列的聚合运算其实就是使用aggregate(使用自定义函数)或者调用mean、std之类的方法。然而,可能希望对不同的列使用不同的聚合函数,或一次应用多个函数,其实这也好办。根据sex和smoker对tips进行分组:

[python] view
plaincopy





>>> import numpy as np

>>> import pandas as pd

>>> tips = pd.read_csv('tips.csv')

>>> # 添加“小费占总额百分比”的列

>>> tips['tip_pct'] = tips['tip']/tips['total_bill']

>>> tips[:6]

total_bill tip sex smoker day time size tip_pct

0 16.99 1.01 Female No Sun Dinner 2 0.059447

1 10.34 1.66 Male No Sun Dinner 3 0.160542

2 21.01 3.50 Male No Sun Dinner 3 0.166587

3 23.68 3.31 Male No Sun Dinner 2 0.139780

4 24.59 3.61 Female No Sun Dinner 4 0.146808

5 25.29 4.71 Male No Sun Dinner 4 0.186240

[python] view
plaincopy





>>> grouped = tips.groupby(['sex', 'smoker'])

>>> grouped_pct = grouped['tip_pct']

>>> grouped

<pandas.core.groupby.DataFrameGroupBy object at 0x03EB3050>

>>> grouped_pct

<pandas.core.groupby.SeriesGroupBy object at 0x03EB3290>

>>> grouped_pct.agg('mean')

sex smoker

Female No 0.156921

Yes 0.182150

Male No 0.160669

Yes 0.152771

Name: tip_pct, dtype: float64

如果传入一组函数或函数名,得到的DataFrame的列就会以相应的函数命名:

[python] view
plaincopy





>>> grouped_pct.agg(['mean', 'std'])

mean std

sex smoker

Female No 0.156921 0.036421

Yes 0.182150 0.071595

Male No 0.160669 0.041849

Yes 0.152771 0.090588

如果传入的是一个由(name, function)元组组成的列表,则各元组的第一个元素就会被用作DataFrame的列名(可以将这种二元元组列表看做一个有序映射):

[python] view
plaincopy





>>> grouped_pct.agg([('mean', 'std'), ('bar', np.std)])

mean bar

sex smoker

Female No 0.036421 0.036421

Yes 0.071595 0.071595

Male No 0.041849 0.041849

Yes 0.090588 0.090588

4、假设我们想要对tip_pct和total_bill列计算三个统计信息:

[python] view
plaincopy





>>> functions = ['count', 'mean', 'max']

>>> result = grouped['tip_pct', 'total_bill'].agg(functions)

>>> result

tip_pct total_bill

count mean max count mean max

sex smoker

Female No 54 0.156921 0.252672 54 18.105185 35.83

Yes 33 0.182150 0.416667 33 17.977879 44.30

Male No 97 0.160669 0.291990 97 19.791237 48.33

Yes 60 0.152771 0.710345 60 22.284500 50.81

说明:

(1)对于DataFrame,可以定义一组应用于全部列的函数,或不同的列应用不同的函数。

(2)结果DataFrame拥有层次化的列,这相当于分别对各列进行聚合,然后用concat将结果组装到一起(列名用作keys参数)。

[python] view
plaincopy





>>> result['tip_pct']

count mean max

sex smoker

Female No 54 0.156921 0.252672

Yes 33 0.182150 0.416667

Male No 97 0.160669 0.291990

Yes 60 0.152771 0.710345

跟前面一样,这里也可以传入带有自定义名称的元组列表:

[python] view
plaincopy





>>> ftuples = [('Durchschnitt', 'mean'), ('Abweichung', np.var)]

>>> grouped['tip_pct', 'total_bill'].agg(ftuples)

tip_pct total_bill

Durchschnitt Abweichung Durchschnitt Abweichung

sex smoker

Female No 0.156921 0.001327 18.105185 53.092422

Yes 0.182150 0.005126 17.977879 84.451517

Male No 0.160669 0.001751 19.791237 76.152961

Yes 0.152771 0.008206 22.284500 98.244673

如果想要对不同的列应用不同的函数,具体的办法是向agg传入一个从列名映射到函数的字典:

[python] view
plaincopy





>>> grouped.agg({'tip':np.max, 'size':'sum'})

tip size

sex smoker

Female No 5.2 140

Yes 6.5 74

Male No 9.0 263

Yes 10.0 150

>>> grouped.agg({'tip_pct':['min', 'max', 'mean', 'std'],

... 'size':'sum'})

tip_pct size

min max mean std sum

sex smoker

Female No 0.056797 0.252672 0.156921 0.036421 140

Yes 0.056433 0.416667 0.182150 0.071595 74

Male No 0.071804 0.291990 0.160669 0.041849 263

Yes 0.035638 0.710345 0.152771 0.090588 150

说明:

只有将多个函数应用到至少一列时,DataFrame才会拥有层次化的列。

5、以“无索引”的形式返回聚合数据

到目前为止,所有示例中的聚合数据都有由唯一的分组键组成的索引(可能还是层次化的)。由于并不总是需要如此,所以你可以向groupby传入as_index=False以禁用该功能。

[python] view
plaincopy





>>> tips.groupby(['sex', 'smoker'], as_index=False).mean()

sex smoker total_bill tip size tip_pct

0 Female No 18.105185 2.773519 2.592593 0.156921

1 Female Yes 17.977879 2.931515 2.242424 0.182150

2 Male No 19.791237 3.113402 2.711340 0.160669

3 Male Yes 22.284500 3.051167 2.500000 0.152771

>>> tips.groupby(['sex', 'smoker'], as_index=True).mean()

total_bill tip size tip_pct

sex smoker

Female No 18.105185 2.773519 2.592593 0.156921

Yes 17.977879 2.931515 2.242424 0.182150

Male No 19.791237 3.113402 2.711340 0.160669

Yes 22.284500 3.051167 2.500000 0.152771

6、参考文献

[1] 四分位数:http://baike.baidu.com/link?url=c744i_30IlKA4Jck9nB-Ti5vn3wJnJUGuHO96O_9ZQYQHi_ai42kQtmM3v-J79MS

[2] 线性插值: http://zh.wikipedia.org/wiki/%E7%BA%BF%E6%80%A7%E6%8F%92%E5%80%BC

[3]《利用Python进行数据分析》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: