Skip to content

pandas 分组统计

pandas 实现groupby 分组统计

python
import pandas as pd
import numpy as np
# %matplotlib inline 是一个 Jupyter Notebook 的魔法命令,用于在 Notebook 中内嵌绘制图形。
%matplotlib inline  

df = pd.DataFrame({'A':['foo', 'bar', 'foo', 'bar', 'foo', 'bar','foo', 'foo'],
                  'B':['one', 'one', 'two', 'three', 'two', 'two','one', 'three'],
                  'C':np.random.randn(8),
                  'D':np.random.randn(8)})
df
df.dtypes
A     object
B     object
C    float64
D    float64
dtype: object

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

python
# 1. 单个列groupby, 查询所有数据列的统计
df.groupby('A').sum()

# 注意:不难看出,新版本的groupby 语法中,开始不再忽略ouject 字符串数据,后面学习使用相关统计语句需要注意,以免发生错误
BCD
A
baronethreetwo-2.6073561.918064
fooonetwotwoonethree-0.6504880.407203
python
# 2. 多个列groupby, 查询所有数据列的统计
df.groupby(['A', 'B']).mean()   #  通过输出可以发现 AB 成对变成了二级索引
CD
AB
barone-0.7790271.223204
three-0.2259120.488460
two-1.6024170.206401
fooone-0.0938220.337233
three-0.9965140.260899
two0.266835-0.264081
python
#避免变成索引的解决方案
df.groupby(['A', 'B'], as_index=False).mean()
python
# 3. 同时查看多种数据统计
# 删除 B 列
df_without_B = df.drop(columns=['B'])
df_without_B.groupby('A').agg(["sum", "mean", "std"])
CD
summeanstdsummeanstd
A
bar-3.405324-1.1351080.689675-1.790008-0.5966691.009874
foo-0.187476-0.0374950.642890-1.830050-0.3660101.197339
python
# 4. 查看单列结果数据统计
# 方法1
df.groupby('A')['C'].agg(["sum", "mean", "std"])
# 方法2
df_without_B.groupby('A').agg(["sum", "mean", "std"])['C']  # 以A列进行分组  进行统计   选出C列
summeanstd
A
bar-3.405324-1.1351080.689675
foo-0.187476-0.0374950.642890
python
# 5. 不同列使用不同的聚合函数
df.groupby('A').agg({'C':'sum', 'D':'mean'})
CD
A
bar-3.405324-0.596669
foo-0.187476-0.366010

遍历groupby 的结果理解执行流程

python
# 1. 遍历单个列聚合的分组
g = df.groupby('A')
g
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x00000287A0D73910>
python
for name, group in g:  # 遍历g  并将名称 和 值分别赋予给 name 和group
    print(name)
    print(group)
    print()
bar
     A      B         C         D
1  bar    one -1.753535  0.172491
3  bar  three -1.260420 -1.740289
5  bar    two -0.391369 -0.222210

foo
     A      B         C         D
0  foo    one -0.124441 -1.483866
2  foo    two  0.950794  1.587760
4  foo    two -0.419235 -0.962665
6  foo    one  0.143290 -0.861839
7  foo  three -0.737884 -0.109441
python
# 获取单个分组数据
g.get_group('bar')
ABCD
1barone-1.7535350.172491
3barthree-1.260420-1.740289
5bartwo-0.391369-0.222210
python
# 遍历多个列聚合的分组
g = df.groupby(['A', 'B'])
for name, group in g:  # 遍历g  并将名称 和 值分别赋予给 name 和group
    print(name)
    print(group)
    print()
# 输出结果可以看到 name 是一个2个元素的tuple ,代表不同的列
('bar', 'one')
     A    B         C         D
1  bar  one -1.753535  0.172491

('bar', 'three')
     A      B        C         D
3  bar  three -1.26042 -1.740289

('bar', 'two')
     A    B         C        D
5  bar  two -0.391369 -0.22221

('foo', 'one')
     A    B         C         D
0  foo  one -0.124441 -1.483866
6  foo  one  0.143290 -0.861839

('foo', 'three')
     A      B         C         D
7  foo  three -0.737884 -0.109441

('foo', 'two')
     A    B         C         D
2  foo  two  0.950794  1.587760
4  foo  two -0.419235 -0.962665
python
# 查询特定值对应的group 数组
g.get_group(('foo', 'one'))
ABCD
0fooone-0.124441-1.483866
6fooone0.143290-0.861839

案例: 分组探索天气数据

python
# 阅读天气数据源文件
fpath = "xxx.wether_data.csv"
df = pd.read_csv(fpath)
# 替换温度后缀 ℃
df.loc[:, "hwendu"] = df["hwendu"].str.replace("C","").astype('int32')
df.loc[:, "lwendu"] = df["lwendu"].str.replace("C","").astype('int32')
# 新增一列为月份
df['month'] = df['ymd'].str[:7] # 对ymd中的数据的前七个字符进行切片 并将结果赋值给month   2018-01-01 --->2018-01

# 案例1: 查看每个月的最高温度
data= df.groupby('month')['hwendu'].max()
data.plot()    # 画图  横坐标为月份 纵坐标为温度

# 案例1: 查看每个月的最高温度、最低温度、平均空气质量指数
group_data = df.groupby('month').agg('hwendu':'max', 'lwendu':'min','aqi':'mean')
group_data.plot()

pandas的 数据转换函数 map apply applymap

map 实现每个值对每个值的映射

apply: series:每个值的处理 DF:每个轴的处理

applymap:(已被弃用)

python
# 公司股票代码到中文的映射  注意,这里是小写  所以要用lower 语法将公司列的值变为小写
dict_company_names = {
    "baidu" :"百度",
    "baba":"阿里巴巴",
    "iqy": "爱奇艺",
    "jd":"京东"
}

stock_history = pd.read_csv('./quotefile/股票历史数据.csv')
# 方法1 Series.map(dict)
stock_history['公司MD'] = stock_history["公司"].str.lower().map(dict_company_names)
stock_history

# 方法2 Series.map(funcation)      funcation的参数是Series的每个元素的值
stock_history["公司MF"] = stock_history["公司"].map(lambda x : dict_company_names[x. lower()])  # 公司力的值 传递给函数x
stock_history

# Series.apply(funcation)
stock_history['公司AF'] = stock_history["公司"].apply(lambda x: dict_company_names[x. lower()])

# DataFrame.apply(funcation)
stock_history['公司DF'] = stock_history.apply(lambda x: dict_company_names[x['公司']. lower()], axis=1)  # 此处的x指代整个DF
stock_history

#applymap 用于DataFrame 所有值的转换
sub_df = stock_history[['收盘', '开盘', '高','低', '交易量']]   # 筛选出五列并赋值给新的DF
    # 数字取整 并应用于所有函数
sub_df.map(lambda x: int(x))

# 直接修改stock_history 的值类型
stock_history.loc[:, ['收盘', '开盘', '高','低', '交易量']] = sub_df.map(lambda x: int(x))
stock_history
日期公司收盘开盘交易量涨跌幅公司MD公司MF公司AF公司DF
02024/3/22IQY4.04.04.03.07.0-0.0074爱奇艺爱奇艺爱奇艺爱奇艺
12024/3/21IQY4.04.04.04.05.0-0.0216爱奇艺爱奇艺爱奇艺爱奇艺
22024/3/20IQY4.04.04.03.06.00.0532爱奇艺爱奇艺爱奇艺爱奇艺
32024/3/19IQY3.03.03.03.05.0-0.0075爱奇艺爱奇艺爱奇艺爱奇艺
42024/3/18IQY3.04.04.03.05.0-0.0050爱奇艺爱奇艺爱奇艺爱奇艺
.......................................
752024/3/1JD23.023.023.022.013.00.0168京东京东京东京东
762024/2/29JD22.022.023.022.014.0-0.0083京东京东京东京东
772024/2/28JD22.023.023.022.015.0-0.0527京东京东京东京东
782024/2/27JD24.024.024.023.09.00.0160京东京东京东京东
792024/2/26JD23.023.024.023.06.0-0.0084京东京东京东京东

80 rows × 12 columns

pandas对每个分组应用apply 函数

image.png

归一化公式

y = (x-最小值)/最大值 - 最小值

案例 对评分数据进行归一化

python
# 实现按照用户ID进行分组, 然后对其中一列进行归一化
def ratings_norm(df):
    # @df: 每个用户分组的DataFrame 

    min_value = df['rating'].min()
    max_value = df['rating'].max()
    df["ratings_norm"] = df["rating"].apply(lambda x: (x-min_value)/max_value-min_value)
    return df

ratings = ratings.groupby("userID").apply(ratings_norm)

pandas 使用stack 和pivot 实现数据透视

python
> **案例: 统计得到电影评分数据集,每个月份的每个分数被评分多少次:(月份,分数1~5,次数)**
python
df_movie_rating = pd.read_csv(xxx.csv)  # 表头包含  UserID  MovieID  Rating  Timestamp(时间戳)

#step1 日期处理
df_movie_rating['pdate'] = pd.to_datetime(df_movie_rating["df_movie_rating"], unit ='s')
# 实现数据统计
df_group = df.groupby([df['pdate'].dt.month, "Rating"])["UserID"].agg(pv=sum)   # 用日期 和rating作为列  px:一个新的列的名称
#  此方法缺点:想查看按月份 不同评分的次数趋势 是没法实现的

# Step2 使用 unstack 实现数据的二维透视(升唯)    目的: 想要画图对比按照月份的不同评分的数量趋势
df_stack = df_group.unstack()
df_stack.plot

# unstack 和stack 是互逆操作  行和列进行互转
# 使用 pivot  简化透视
df_reset = df_group.reset_index()  # 重溅索引
df_pivot = df_reset.pivot('pdate', 'Rating','pv')
python
# **19 pandas 使用apply 函数给表格同时添加多列**

© 2023-2024 LiuJingcheng. 保留所有权利。