饮冰三年-人工智能-Pandas-81-Pandas 数据分析-分组统计

上一篇:饮冰三年-人工智能-Pandas-80-Pandas 数据扩增

 数据准备可参考:饮冰三年-人工智能-Django淘宝拾遗-75-数据准备

一、分组统计

Pandas的分组聚合groupby 首先使用groupby先对数据进行分组,然后在对每一个分组使用聚合、转换函数

 一、分组使用聚合函数做数据统计

0、数据准备

df = pd.DataFrame({'A': ['foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'foo'],
                       'B': ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'],
                       'C': np.random.randint(10, size=8),
                       'D': np.random.randint(10, size=8)})
    print(df)
数据准备
     A      B  C  D
0 foo one 5 7
1 bar one 6 7
2 foo two 1 8
3 bar three 3 2
4 foo two 3 9
5 bar two 2 3
6 foo one 5 7
7 foo three 4 0

1、单个列group by,查询所有数据列的统计

语法:df.groupby('字段').sum()  #对字段列进行分组,按分组结果进行求和统计,字段列会变成索引列

# 1、单个列group by,查询所有数据列的统计
df_group_by_1 = df.groupby('A').sum()
print(df_group_by_1)
单个列group by
    """
          C   D
    A          
    bar  11  12
    foo  18  31
    """
    """
    由上可知:
    df.groupby('字段').sum()  #对字段列进行分组,按分组结果进行求和统计,字段列会变成索引列
    1:group by 中的‘A’变成了数据的索引列
    2:因为要统计sum,但是‘B'列不是数字,所以被自动忽略。
    """
结果

2、多个列group by,查询所有数据列的统计

语法:df.groupby(['字段1','字段2']).mean()  #对多个字段进行分组,先按照字段1分,然后按照字段2分,最后进行平均值操作

# 2、多个列group by,查询所有数据列的统计
df_group_by_2 = df.groupby(['A', 'B']).mean()
print(df_group_by_2)
多个列group by
    """
                 C    D
    A   B              
    bar one    6.0  7.0
        three  3.0  2.0
        two    2.0  3.0
    foo one    5.0  7.0
        three  4.0  0.0
        two    2.0  8.5
    """
    """
    由上可知:
    df.groupby(['字段1','字段2']).mean()  #对多个字段进行分组,先按照字段1分,然后按照字段2分,最后进行平均值操作
    1:group by 中的(‘A’和’B‘)成对变成了二级索引
    """
结果

语法:df.groupby(['字段1','字段2'],as_index=False).mean()  #对多个字段进行分组, 将分组字段变成普通的列

# 2-1、将A和B变成普通的列
df_group_by_2_1 = df.groupby(['A', 'B'], as_index=False).mean()
print(df_group_by_2_1)
多个列group by 并保留为普通列
    """
         A      B    C    D
    0  bar    one  6.0  7.0
    1  bar  three  3.0  2.0
    2  bar    two  2.0  3.0
    3  foo    one  5.0  7.0
    4  foo  three  4.0  0.0
    5  foo    two  2.0  8.5
    """
结果

3、同时查看多种数据统计

语法:df.groupby('字段').sum([np.sum, np.mean, np.std])  #还是按指定字段分组,但会生成多列其他数据

df_group_by_3 = df.groupby('A').agg([np.sum, np.mean, np.std])
print(df_group_by_3)
同时查看多种数据统计
    """
          C                       D               
        sum      mean       std sum mean       std
    A                                             
    bar  11  3.666667  2.081666  12  4.0  2.645751
    foo  18  3.600000  1.673320  31  6.2  3.563706
    """
    """
    列变成了多级索引
    df.groupby('字段').agg([np.sum,np.mean,np.std])  #还是按指定字段分组,但会生成多列其他数据
    """
结果

4、查看单列的结果数据统计

语法:df.groupby('字段1')['字段2'].agg([np.sum,np.mean,np.std])

# 方法一、预过滤,性能更好
    df_group_by_4_1 = df.groupby('A')['C'].agg([np.sum, np.mean, np.std])
    print(df_group_by_4_1)
方法一
    """
         sum      mean       std
    A                           
    bar   11  3.666667  2.081666
    foo   18  3.600000  1.673320
    """
    """
    查看,但只看一列的多种统计结果
    df.groupby('字段1')['字段2'].agg([np.sum,np.mean,np.std])
    """
方法一:结果

语法:df.groupby('字段1').agg([np.sum,np.mean,np.std])['字段2']

# 方法二、过滤放到后面
    df_group_by_4_2 = df.groupby('A').agg([np.sum, np.mean, np.std])['C']
    print(df_group_by_4_2)
方法二
    """
         sum      mean       std
    A                           
    bar   11  3.666667  2.081666
    foo   18  3.600000  1.673320
    """
    """
    查看,但只看一列的多种统计结果
    df.groupby('字段1').agg([np.sum,np.mean,np.std])['字段2']
    """
方法二:结果

5、不同列使用不同的聚合函数

语法:df.groupby('字段1').agg({"字段2":np.sum,"字段3":np.mean}) #结果字段2列值为和,字段3列值为平均值

df_group_by_5 = df.groupby('A').agg({'C': np.sum, 'D': np.mean})
print(df_group_by_5)
不同列使用不同的聚合函数
    """
          C    D
    A           
    bar  11  4.0
    foo  18  6.2
    """
    """
    不同列使用不同聚合函数
    df.groupby('字段1').agg({"字段2":np.sum,"字段3":np.mean})  #结果字段2列值为和,字段3列值为平均值
    """
结果

 

 二、for循环遍历groupby的每个分组

0、数据准备

数据准备
     A      B  C  D
0 foo one 5 4
1 bar one 7 7
2 foo two 6 9
3 bar three 5 6
4 foo two 9 4
5 bar two 3 0
6 foo one 7 0
7 foo three 9 1

1、单个列group by,查询所有数据列的统计

语法:df.groupby('字段')

    g1 = df.groupby("A")
    for name, group in g1:
        print(name, group)
利用get_group()获取单个分组
    """
         A      B  C  D
    0  foo    one  5  4
    1  bar    one  7  7
    2  foo    two  6  9
    3  bar  three  5  6
    4  foo    two  9  4
    5  bar    two  3  0
    6  foo    one  7  0
    7  foo  three  9  1
    bar      A      B  C  D
    1  bar    one  7  7
    3  bar  three  5  6
    5  bar    two  3  0
    foo      A      B  C  D
    0  foo    one  5  4
    2  foo    two  6  9
    4  foo    two  9  4
    6  foo    one  7  0
    7  foo  three  9  1
    """
结果

2、多个列group by,查询所有数据列的统计

语法:df.groupby(['字段1','字段2'])

    g2 = df.groupby(["A", "B"])
    for name, group in g2:
        print(name)
        print(group)
多个列分组
"""
    ('bar', 'one')
         A    B  C  D
    1  bar  one  7  7
    ('bar', 'three')
         A      B  C  D
    3  bar  three  5  6
    ('bar', 'two')
         A    B  C  D
    5  bar  two  3  0
    ('foo', 'one')
         A    B  C  D
    0  foo  one  5  4
    6  foo  one  7  0
    ('foo', 'three')
         A      B  C  D
    7  foo  three  9  1
    ('foo', 'two')
         A    B  C  D
    2  foo  two  6  9
    4  foo  two  9  4
    """
结果

通过get_group()获取其中某一个分组

    print("获取某个分组")
    print(g2.get_group(('foo', 'one')))  # 这里面的参数 name 为两个元素的tuple,
    """
         A    B  C  D
    0  foo  one  5  4
    6  foo  one  7  0
    """
获取某个分组
    # 可以直接查询group后的某几列,生成Series或者子DataFrame
    print("直接查询group后的某几列")
    for name, group in g2["C"]:
        print(name)
        print(group)
        print(type(group))
    """
    ('bar', 'one')
    1    7
    Name: C, dtype: int32
    <class 'pandas.core.series.Series'>
    ('bar', 'three')
    3    5
    Name: C, dtype: int32
    <class 'pandas.core.series.Series'>
    ('bar', 'two')
    5    3
    Name: C, dtype: int32
    <class 'pandas.core.series.Series'>
    ('foo', 'one')
    0    5
    6    7
    Name: C, dtype: int32
    <class 'pandas.core.series.Series'>
    ('foo', 'three')
    7    9
    Name: C, dtype: int32
    <class 'pandas.core.series.Series'>
    ('foo', 'two')
    2    6
    4    9
    Name: C, dtype: int32
    <class 'pandas.core.series.Series'>
    """
可以直接查询group后的某几列

总结

  整个groupby 流程:

  1. 首先 按照key 进行分组,得到(group名称,group本身),group本身是dataframe或者series。
  2. 其次 计算,在group本身进行各种统计函数的计算。
  3. 统计 将key和计算结果拼接起来。

 三、实例演示

0、数据准备

    # 获取数据
    df = get_data_from_db()
    df = df[["id", "profession_name", "course_name", "student_name", "score_total"]]
    print(df)
    """
          id   profession_name     course_name     student_name  score_total
    0      7           经济与管理        语文-经         小明-经         77.0
    1      8           经济与管理        语文-经         小红-经         60.0
    2      9           经济与管理        语文-经         小花-经         50.0
    3     10           经济与管理        语文-经         张三-经        100.0
    ......
    """
获取数据

1、查看每个专业的最高成绩

# 1:查看每个专业的最高成绩-- select max(score_total) from tb_score group by profession_name
    data_1 = df.groupby('profession_name')["score_total"].max()
    print(data_1)
    """
    profession_name
    挖掘机      100.0
    文学与历史    100.0
    经济与管理    100.0
    计算机      100.0
    """
查看每个专业的最高成绩

2、查看每个专业的最大ID、平均分

# 2:查看每个专业的最大ID、平均分 select max(id),avg(score_total) from tb_score group by profession_name
    data_2 = df.groupby('profession_name').agg({"id": np.max, "score_total": np.mean})
    print(data_2)
    """
                      id  score_total
    profession_name                  
    挖掘机              486     67.62931
    文学与历史           462     67.37500
    经济与管理           414     67.37500
    计算机              438     67.37500
    """
:查每个专业的最大ID、平均分

 

 四、分组之后应用apply函数

 

 这里我们可以自己实现apply函数

GroupBy.apply(function)

  1. function的第一个参数是dataframe
  2. function的返回结果,可以是dataframe、series、单个值、设置和输入dataframe完全没有关系

示例1:对学生成绩按照分组归一化

将不同范围的数值进行归一化,映射到[0,1]区间

def score_norm(df):
    """
    实现按照学生名称分组,然后对其中一列归一化
    df :每个学生分组的dataframe
    """
    min_value = df["score_total"].min()
    max_value = df["score_total"].max()
    df["score_norm"] = df["score_total"].apply(lambda x: (x - min_value) / (max_value - min_value))
    return df

def test_group_apply():
    # 获取数据
    df = get_data_from_db()
    df = df[["id", "profession_name", "course_name", "student_name", "score_total"]]
    print(df)
    """
          id   profession_name     course_name     student_name  score_total
    0      7           经济与管理        语文-经         小明-经         77.0
    1      8           经济与管理        语文-经         小红-经         60.0
    2      9           经济与管理        语文-经         小花-经         50.0
    3     10           经济与管理        语文-经         张三-经        100.0
    ......
    """
    # 1:每个学生的成绩不同,有的实力强,有的实力弱,按学生做归一化处理
    data_1 = df.groupby('student_name').apply(score_norm)
    print(data_1)
    """
          id        profession_name course_name student_name  score_total  score_norm
    0      7           经济与管理        语文-经         小明-经         77.0    0.857143
    1      8           经济与管理        语文-经         小红-经         70.0    1.000000
    2      9           经济与管理        语文-经         小花-经         50.0    0.672131
    3     10           经济与管理        语文-经         张三-经        100.0    1.000000
    4     11           经济与管理        语文-经         李四-经         80.0    0.897436
    ..   ...             ...         ...          ...          ...         ...
    475  482             挖掘机     挖掘机实操-挖         小红-挖           60    0.000000
    476  483             挖掘机     挖掘机实操-挖         小花-挖            9    0.000000
    477  484             挖掘机     挖掘机实操-挖         张三-挖           98    0.969231
    478  485             挖掘机     挖掘机实操-挖         李四-挖           80    0.897436
    479  486             挖掘机     挖掘机实操-挖         王五-挖           90    1.000000
    """
成绩分组归一化处理

示例2:获取每个专业的分数最高的前2名

def score_norm(df):
    """
    实现按照学生名称分组,然后对其中一列归一化
    df :每个学生分组的dataframe
    """
    min_value = df["score_total"].min()
    max_value = df["score_total"].max()
    df["score_norm"] = df["score_total"].apply(lambda x: (x - min_value) / (max_value - min_value))
    return df


def score_top(df, topn):
    """
    怎样获取每个分组的TOP N数据
    df :每个学生分组group的df
    """
    return df.sort_values(by="score_total",ascending=False )[["student_name", "score_total"]][:topn]


def test_group_apply():
    # 获取数据
    df = get_data_from_db()
    df = df[["id", "profession_name", "course_name", "student_name", "score_total"]]
    print(df)
    """
          id   profession_name     course_name     student_name  score_total
    0      7           经济与管理        语文-经         小明-经         77.0
    1      8           经济与管理        语文-经         小红-经         60.0
    2      9           经济与管理        语文-经         小花-经         50.0
    3     10           经济与管理        语文-经         张三-经        100.0
    ......
    """
    # 1:每个学生的成绩不同,有的实力强,有的实力弱,按学生做归一化处理
    data_1 = df.groupby('student_name').apply(score_norm)
    print(data_1)
    """
          id        profession_name course_name student_name  score_total  score_norm
    0      7           经济与管理        语文-经         小明-经         77.0    0.857143
    1      8           经济与管理        语文-经         小红-经         70.0    1.000000
    2      9           经济与管理        语文-经         小花-经         50.0    0.672131
    3     10           经济与管理        语文-经         张三-经        100.0    1.000000
    4     11           经济与管理        语文-经         李四-经         80.0    0.897436
    ..   ...             ...         ...          ...          ...         ...
    475  482             挖掘机     挖掘机实操-挖         小红-挖           60    0.000000
    476  483             挖掘机     挖掘机实操-挖         小花-挖            9    0.000000
    477  484             挖掘机     挖掘机实操-挖         张三-挖           98    0.969231
    478  485             挖掘机     挖掘机实操-挖         李四-挖           80    0.897436
    479  486             挖掘机     挖掘机实操-挖         王五-挖           90    1.000000
    """
    # 2:获取每个专业的分数最高的2名
    data_2 = df.groupby('profession_name').apply(score_top, topn=2)
    print(data_2)
    """                    
                            student_name   score_total
    profession_name                                 
    挖掘机           267           张三-挖          100
                    471           张三-挖           99
    文学与历史        339           张三-文          100
                    351           张三-文          100
    经济与管理        291           张三-经          100
                    303           张三-经          100
    计算机           315           张三-计          100
                    327           张三-计          100
    """
专业最高成绩前两名学生

 

posted @ 2022-12-13 16:59  逍遥小天狼  阅读(84)  评论(0编辑  收藏  举报