文章数据
收藏(次)

【python数据分析】第十章 数据聚合与分组运算-2

加关注
数据聚合
--------------------------------------------------------------------------------
聚合指的是任何能够从数组产生标量值的数据转换过程(一组数据变成一个数据,求和,平均...)
--------------------------------------------------------------------------------
聚合方法:
count 非NA数值数量
sum 非NA和
mean 非NA平均
median 中位数
std,var 无偏(分母n-1)标准差和方差
min,max 非NA 最值
prod 非NA的值积
first, last 第一个或者最后一个非NA的值
--------------------------------------------------------------------------------
#使用聚合函数
df.groupby('key1').sum()

如果使用自己的聚合函数,分组以后使用 agg(fun) 或者 aggregate(fun)即可:参数是一组数据
df.groupby('key1').agg(lambda x: x.max() - x.min())
df.groupby('key1').aggregate(lambda x: x.max() - x.min())


# describe 是已经定义好的,一组统计数据,
df.groupby('key1').describe()
data1 data2
count mean std min 25% 50% 75% max count mean std min 25% 50% 75% max
.........
--------------------------------------------------------------------------------
向 df.groupby('key1').describe() 这样,一次计算多种统计数据,
df = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'],
'key2' : ['one', 'two', 'one', 'two','one'],
'data1' : [2,8,4,2,6],
'data2' : [1,7,4,3,5]})

fu = lambda x:x.max()-x.min()
df.groupby(['key1']).agg(['mean', 'sum',fu, 'std'])
# 这里 fu 不能直接写 lambda表达式,因为,数据计算以后会有表头,直接lambda表达式,这个表头没法弄
# 而且,fu 是我们自定义的,不能是写字符串'fu'。 那些是包里定义的聚合方法,所以写字符串他们认识。
输出:
data1 data2
mean sum <lambda_0> std mean sum <lambda_0> std
key1
a 5.333333 16 6 3.055050 4.333333 13 6 3.055050
b 3.000000 6 2 1.414214 3.500000 7 1 0.707107

但是 现在的表头是 <lambda_0>, 没有表现力,需要改,使用元组的方式,(前面名称,方法)
df.groupby(['key1']).agg(['mean', 'sum', ('p_t_p', fu), ('bzc','std')])

对指定的列执行一系列方法:每个指定的列都执行指定的聚合方法
df.groupby(['key1'])[['data1', 'data2']].agg([('ptp',fu), 'mean'])
--------------------------------------------------------------------------------
指定的列计算不同的方法,比如第一列计算求和与平均,第二列计算间距
df.groupby(['key1'])[['data1', 'data2']].agg({'data1':['sum', 'mean'], 'data2':[fu]})
--------------------------------------------------------------------------------
以“没有行索引”的形式返回聚合数据
现在 df.groupby('key1').mean() 得到的数据的行索引就是分组的 key1 中的值
df.groupby('key1').mean() 输出:
data1 data2
key1
a 5.333333 4.333333
b 3.000000 3.500000

不要让分组的值成为结果的索引,相当于让他把索引变成普通数据,然后再重新索引
df.groupby('key1', as_index=False).mean()
输出:
key1 data1 data2
0 a 5.333333 4.333333
1 b 3.000000 3.500000
================================================================================
apply:一般性的“拆分-应用-合并”
--------------------------------------------------------------------------------
df = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a', 'a', 'a', 'b', 'a'],
'key2' : ['one', 'two', 'one', 'two','one', 'two', 'two', 'one', 'one'],
'data1' : [2,8,4,2,6,3,5,6,7],
'data2' : [1,7,4,3,5,2,3,1,6]})
要求:按照 key1 进行分组,分成 a 组和b组, 取出两组中 data1 最大的2个
值(组中,data1最大的2个值),所在的整行数据

df 的输出:
key1 key2 data1 data2
0 a one 2 1
1 a two 8 7
2 b one 4 4
3 b two 2 3
4 a one 6 5
5 a two 3 2
6 a two 5 3
7 b one 6 1
8 a one 7 6

a 组中 data1 最大2个值的两条是:
1 a two 8 7
8 a one 7 6
--------------------------------------------------------------------------------
定义一个方法,能够给某列数据排序,然后取出最大的N个数据 所在的行
def myfu(df, n=1, col='data1'):
print(col)
return df.sort_values(col)[-n:]

使用 apply 方式传入 自定义的方法,如果自定义的方法有参数,继续写在后面就是了
比如:# df.groupby(['key1']).apply(myfu, n=2, col='key2')
本例中 myfu 被调用两次, myfu 参数的值依次是 df.loc[df['key1'] == 'a', :] 和 df.loc[df['key1'] == 'b', :]

df.groupby(['key1']).apply(myfu, 2)
输出:
key1 key2 data1 data2
key1
a 8 a one 7 6
1 a two 8 7
b 2 b one 4 4
7 b one 6 1

索引a b 后面的列 8 1 2 7 是df的默认行索引,现在有新索引,他们只是照搬下来的,不是数据
--------------------------------------------------------------------------------
我们把上面的自定方法修改一些,不是返回 df 的全部数据,而是指定列的数据
def myfu(df, n=1, col='data1'):
return df[col].sort_values()[-n:]

df.groupby(['key1']).apply(myfu, 2) # 执行方法,发现输出变化了,
输出:
key1
a 8 7
1 8
b 2 4
7 6
Name: data1, dtype: int64
结论就是我们自定的方法在返回后,被 apple 进行组装。 我们多次返回每组中的数据,apply
一次返回每组数据的组装数据。我们返回的数据决定了数据的形式。
--------------------------------------------------------------------------------
上面 apple 得到的结果使用了 分组键作为新数据的索引,如果不需要就使用 group_keys=False 去掉
df.groupby(['key1'], group_keys=False).apply(myfu, 2)
================================================================================
分位数和桶分析
--------------------------------------------------------------------------------
# 生成一个 DataFrame 对象,两列 随机数
frame = pd.DataFrame({'data1': np.random.randn(1000),'data2': np.random.randn(1000)})

# 把 data1 这列分成4个等分区间,quartiles 中保存了4个等分区间,还有data1每个数据属于哪个区间的列表
quartiles = pd.cut(frame.data1, 4)

# 他会看看 data2 是不是也在这个区间,在同一个区间的数据被分成1组
grouped = frame.data2.groupby(quartiles)

# 自定义方法
def get_state(grp):
return{'min':grp.min(), 'max':grp.max(), 'count':grp.count(), 'mean':grp.mean()}


# 把分好组的数据依次使用 自定的方法。
grouped.apply(get_state).unstack()
--------------------------------------------------------------------------------
应用:
填充 NA 数据,
s = pd.Series([1,np.nan, 9, np.nan, 2, np.nan])
s.fillna(s.mean()) # 平均值是 4, 计算和以及数据数量时,na 数据都忽略。
比如现在有一组数据,男女身高,里面有NA 数据,想用平均数进行填充,这时不能使用
全体数据的平均值填充,而是 男生的使用男生平均身高,女生使用女生的,这样才准确
frame = pd.DataFrame({
'name':['zs', 'li','ll', 'sd', 'ds', 'd2', 'as', 'jk', 'sw'],
'gender':[1, 2, 2, 1, 1, 1, 2, 1, 2],
'tall' :[178, 155, np.nan, np.nan, 183, 167, 168, np.nan, 163]
})

frame.groupby('gender', group_keys=False).apply(lambda x:x.fillna(x.mean()))
输出: 但是会把原数据的顺序改掉。怎么办

name gender tall
0 zs 1 178.0
3 sd 1 176.0
4 ds 1 183.0
5 d2 1 167.0
7 jk 1 176.0
1 li 2 155.0
2 ll 2 162.0
6 as 2 168.0
8 sw 2 163.0
--------------------------------------------------------------------------------
Series.sample(N) 随机抽样,获取Series 样本中的随机N个样本点
--------------------------------------------------------------------------------
np.average([12,3,4,5], weights=[0.9,0.2, 0.5, 0.8]) # avg = sum(a * weights) / sum(weights)
--------------------------------------------------------------------------------



>> 目录 << 


 

分享
收藏
点赞人
举报
文章标签
评论列表

推荐

暂无推荐