#%%
# CY3761 | 2022-01-13 10:08
#%%
# 此为 jupyter 模版, 执行 build 后记住先执行-全部运行
# 使用 DataSpell 进行编写文档
# 变量名、函数名小写分段处理
#%%
# 导入项
import numpy as np
import pandas as pd
np.array((np, pd))
#%%
class JsonObject:
def __init__(self, items):
self.items = items
def __getattribute__(self, name: str): # 注意这个方法有个坑里面不能写入 self.* 否则会出现 循环调用
return object.__getattribute__(self, 'items').get(name)
def print_data(o):
o_items = dict(shape=None,size=None, index=None,columns=None, dtype=None,dtypes=None,)
print('type\t: %s' % type(o))
for (k,v) in o_items.items():
try:
o_items[k] = eval(f'o.{k}')
except (Exception, BaseException):
pass
if k == 'dtypes':
o_items[k] = {k:str(v) for k,v in dict(o_items[k]).items() }
print('%s\t: %s' % (k, o_items[k]))
print()
display(o)
def get_new_file_path(file_path, string, file_ext=None):
file_sep = '.'
file_path_split = file_path.split(file_sep)
file_path_split_pop = file_path_split.pop() # 获取最后一个
file_ext = file_path_split_pop if not file_ext else file_ext
return file_sep.join(file_path_split) + '-' + string + file_sep + file_ext
r_rang = 26
r_chr = {k: [chr(_) for _ in range(size, size+r_rang)] for k,size in dict(b=65, s=97).items()} # 大写字母索引 小写字母索引
r_chr = pd.DataFrame(r_chr, index=range(1, r_rang+1)) # 字母表 b: 大写 s: 小写 1 开始
def get_chr_items(k, f):
k = k.lower()
f = f.upper() if k == 'b' else f.lower()
return tuple(r_chr[k][:list(r_chr[k]).index(f) + 1])
display(r_chr)
r_df = pd.DataFrame(np.random.randint(0, 100, (10, 10)), tuple(r_chr.b[:10]), tuple(r_chr.s[:10]))
# print_data(r_df)
#%% md
# 分组聚合
#%% md
## 分组
#%%
df_01 = pd.DataFrame(
dict(
sex=np.random.randint(0, 2, 300), # 性别: 0-男 1-女
cls=np.random.randint(1, 9, 300), # 班级: 1-8 8个班
P=np.random.randint(0, 151, 300), # P科成绩
K=np.random.randint(0, 151, 300), # K科成绩
J=np.random.randint(0, 151, 300), # J科成绩
T=np.random.randint(0, 151, 300), # T科成绩
C=np.random.randint(0, 151, 300), # C科成绩
)
)
# 重新设置性别列
df_01.sex = df_01.sex.map({0: '男', 1: '女'})
df_01.head()
#%%
# 分组->可迭代对象
g_01 = df_01.groupby(by='sex') # 按性别 单分组 | [['P','J']]
len(list(g_01)) # g_01 可迭代对象 <pandas.core.groupby.generic.DataFrameGroupBy object at 0x00000240D6033070> | 单分组是 对应列的值的条数(去重)
#%%
for a, b in g_01:
print(a)
display(b.head()) # 拆分成2组表格数据
#%%
# 多分组
g_02 = df_01.groupby(by=['cls', 'sex']) # 按班级、性别
print(len(list(g_02))) # 多分组 是对应分组列条数(去重)乘积 2*8=16
for a, b in g_02:
print(a)
# display(b.head(1)) # 拆分成2组表格数据
#%%
# 对一列值进行分组
g_03 = df_01.P.groupby(df_01.cls) # 通过班进行分组 单分组
print('长度', len(list(g_03)))
for a, b in g_03:
print(a, '\b班P学科成绩', np.array(b.head())) #
#%%
g_04 = df_01.K.groupby([df_01.cls, df_01.sex])
print('长度', len(list(g_04)))
for a, b in g_04:
print('%s班%s生K学科成绩' % (a[0], a[1]), np.array(b.head())) #
#%%
## 按数据类型进行分组
g_05 = df_01.groupby(df_01.dtypes, axis=1)
print('长度', len(list(g_05)))
for a, b in g_05:
print('组名(数据类型)', a, b.shape, b.size)
display(b.head())
#%%
# 按字典进行分组 | 设定键(列名)=值(分组名) | 这类似数据表中筛选字段..
g_06 = df_01.groupby(dict(
sex='category', cls='category',
P='IT', K='IT', T='IT', J='IT', C='IT'
), axis=1)
print('长度', len(list(g_06)))
for a, b in g_06:
print('组名', a, b.shape, b.size)
display(b.head())
#%% md
## 分组聚合
#%%
# 分组直接调用函数进行聚合
df_01.groupby('sex').mean().round(2) # 按性别分组 然后求平均分
#%%
df_01.groupby('sex').count() # 按性别分组 然后求条数
#%%
df_01.groupby('sex').sum() # 按性别分组 然后求总数
#%%
# 按照班级和性别进行分组,Python、Keras的最大值聚合
df_01.groupby(['cls', 'sex'])[['P','K']].max()
#%%
df_01.groupby(['cls', 'sex'])[['P','K']].max().T # 数据垂直了
#%%
# 按照班级和性别进行分组,计数聚合。统计每个班,男女人数
df_01.groupby(['cls','sex']).size() # 不是用 count sum会把其他科目的也进行计算
#%%
# 基本描述性统计聚合
df_01.groupby(['cls', 'sex']).describe()
#%% md
## 分组聚合apply、transform
#%%
g_07 = df_01.groupby(['cls', 'sex'])
for a,b in g_07: # 按班别、性别分组 8*2=16
print(a, b.shape) # 班别 性别 数据条数 数据列数
# display(b.head(1))
#%%
g_07[['P', 'K']].apply(np.mean).round(2) # 使用 apply进行分组聚合 | 平均值
#%%
df_01[['sex', 'cls', 'P', 'K']].head()
#%%
# transform 需要查元数据 数据第一行 0对应元数据第一行 (女,3班) => 查看 女生3班平均分是否是 P: 64.18 K: 88.29 | 3,女,64.18,88.29 .. 尼玛
df_02 = g_07[['P', 'K']].transform(np.mean).round(2) # 使用 transform进行分组聚合 | 啥数据? 一组数据 300 个学生的 | 这也是返回各班各科的平均分 只是对应着每个学生 学生 0是3班女的.. 1是1班男的
print(df_02.shape)
df_02.head() # 0,64.18,88.29 | 1,80.91,78.50
#%%
g_07[['P','J']].apply(lambda _: np.mean(_)).round(2) # 调用自定义函数也可以 这里返回的也是分组平均值
#%%
func_01 = lambda _: (_ - _.min() / (_.max() - _.min()))
g_07[['P','J']].apply(func_01).round(2) # 调用自定义函数 有时候返回的 返回结果与transform一样
#%%
g_07[['P','J']].transform(func_01).round(2) # 最大值最小值归一化?
#%% md
## 分组聚合agg
#%%
g_07[['T', 'K']].agg([np.min, np.max, pd.Series.count]) # 分组后使用多种统计方式
#%%
# 分组后不同属性应用多种不同统计汇总
g_07[['P','K']].agg(dict(
P=[('最大值', np.max), ('最大值', np.max), ('最小值', np.min), ('平均值', np.mean)],
K=[('计数', pd.Series.count), ('中位数', np.median)]
))
#%% md
## 透视表pivot_table
#%%
df_01.pivot_table(
values=['P', 'K', 'T'], # 需要透视分组的列
index=['cls', 'sex'], # 需要透视的指标
aggfunc=dict( # 聚合运算
P=[('最小值', np.min)],
K=[('最大值', np.max), ('中位数', np.median)],
T=[('最小值', np.min), ('平均值', np.mean), ('计数', len)]
)
).round(0)
#%%
PY-pandas | 分组聚合
最新推荐文章于 2024-09-26 19:15:00 发布