【数据分析】Pand函数详解进阶:案例解析(第26天)

系列文章目录


  1. 分组对象操作
  2. 分组聚合
  3. 分组转换
  4. 分组过滤
  5. 分箱
  6. 合并操作
  7. 变形操作


前言

本文通过案例分析的方式详解了Pandas函数进阶常用操作。


提示:以下是本篇文章正文内容,下面案例可供参考

1 分组对象操作

  • 获取分组对象

    import pandas as pd
    # 加载数据集
    df = pd.read_csv('data/LJdata.csv')
    df
    # 实现分组操作是通过 groupby() 方法, 得到分组对象
    # 对区域列进行分组操作
    gs1 = df.groupby(by=['区域'])
    gs1
    type(gs1)
    # 对多列进行分组操作
    gs2 = df.groupby(by=['区域', '户型'])
    gs2
    type(gs2)
    
  • 分组对象聚合操作

    # gs1是分组之后的df对象, 直接调用聚合函数是对所有数值列进行聚合操作
    gs1.mean()
    # 获取分组df对象中某列数值列进行聚合操作
    # 获取df中的列, df[列名]
    print(gs1['价格'])
    gs1[['价格', '面积']]
    gs1['价格'].max()
    
  • 获取分组对象第一条或最后一条数据

    # 获取每组中的第一条数据
    gs2.first()
    gs1.first()
    # 获取每组中的最后一条数据
    gs2.last()
    
  • 获取分组对象分组信息

    # 获取分组
    gs2.grouper.result_index
    gs1.grouper.result_index
    # 获取每组数据的索引值
    gs1.groups
    
  • 获取分组对象分组数据

    gs2.get_group(name=('七里庄租房', '1室0厅'))
    gs2.get_group(name=('CBD租房', '2室1厅'))
    gs1['价格'].get_group(name='CBD租房')
    

2 分组聚合

2.1 df分组对象直接调用聚合函数

# df分组后直接调用聚合函数, 对df分组对象的所有数值列进行相同的聚合操作
# df.groupby(by=[分组列名1, 分组列名2, ...]).max/min/mean/sum/count()
# 对区域进行分组, 统计面积,价格以及看房人数列的平均值
df.groupby(by='区域').mean()
df.groupby(by=['区域']).count()

2.2 df分组对象指定聚合列

# df分组后对单列或多列进行聚合操作
# df.groupby(by=[列名1, 列名2, ...])[[列名]].聚合函数()  -> 一个[], 得到s对象; 两个[],得到df对象
# df.groupby(by=[列名1, 列名2, ...])[[列名1, 列名2, ...]].聚合函数()
# 对区域分组, 统计价格列的最小值, 一个[]返回s对象
df.groupby(by='区域')['价格'].min()
# 对区域分组, 统计价格列的最小值, 两个[]返回df对象
df.groupby(by='区域')[['价格']].min()
# 对区域分组, 统计价格和看房人数的求和
df.groupby(by=['区域'])[['价格', '看房人数']].sum()

2.3 df分组对象结合agg函数

  • 多个聚合函数

    # df分组后使用多个聚合函数
    # df.groupby(by=[列名1. 列名2, ...])[[列名1, 列名2...]].agg([聚合函数名1, 聚合函数名2, ...])
    # 对列名1进行多个聚合操作, 列名2进行多个聚合操作
    # 聚合函数名可以是pandas内置的函数名 'max', 'min';也可以是numpy中的函数名 np.mean np.sum; 直接使用python的聚合函数 max min
    import numpy as np
    # 对户型分组, 统计面积和价格列的最小值,平均值以及求和
    df.groupby(by='户型')[['面积', '价格']].agg([min, np.mean, 'sum'])
    
  • 不同列使用不同聚合函数

    # df分组后不同列使用不同聚合函数
    # df.groupby(by=[列名1, 列名2, ...]).agg({列名1:聚合函数名1, 列名2:聚合函数名2, ...})
    # 对户型分组, 统计面积的最大值以及价格的平均值
    df.groupby('户型').agg({'面积':max, '价格':np.mean})
    
  • 使用自定义函数

    # df分组后使用自定义的函数进行聚合操作  参考apply()函数
    # df.groupby(by=[列名1, 列名2, ...])[[列名1, 列名2, ...]].agg(自定义函数名, 参数2=, 参数3=)
    # 手写求平均聚合操作
    # 自定义函数最少接收一个参数, 分组后每组的数据
    def avg_func(x, arg1):
        print('x的值是->', x)
        # 平均值 = 求和值 / 个数
        # x.sum()求和
        # x.size 统计个数
        m = x.sum() / x.size
        return m + arg1
    df.groupby('户型')['价格'].agg(avg_func, arg1=10)
    
    # 手写求平均聚合操作
    # 自定义函数最少接收一个参数, 分组后每组的数据
    def avg_func(x, arg1):
        print('x的值是->', x)
        print(type(x))
        # 平均值 = 求和值 / 个数
        # sum()求和
        # size 统计个数
        m = x['价格'].sum() / x['价格'].size
        return m + arg1
    
    # 自定义函数中的x参数是df分组数据
    df.groupby('户型').agg(avg_func, arg1=10)
    
    def func(s):
        print('s的值是->', s)
        # 参数s是分组之后指定的每一列
        s_mean = s.sum() / s.size
        return s_mean 
    
    
    res = df.groupby('户型')[['价格', '看房人数']].agg(func)
    print(res)
    

3 分组转换

分组转换和分组聚合
分组转换是每组的聚合结果, 然后拼接到df后边, 不会改变df的行数; 分组之前的df有多少上数据, 分组转换之后还是多少行
分组聚合是每组的聚合结果和每组信息一同返回, 改变df的行数, 有多少分组返回多少行数据

# df分组之后对列进行转换(计算)操作
# df.groupby(by=[列名1, 列名2, ...])[[列名1, 列名2, ...]].transform(聚合函数)
df.groupby('户型')['价格'].agg('mean')
# 对户型分组, 统计价格列的平均值, 添加到原df后边
df.groupby('户型')['价格'].transform('mean')
# 类似于sql中的开窗函数
df['平均价格'] = df.groupby('户型')['价格'].transform('mean')
df

# transform(自定义函数名)
# 手写求平均值的函数
def func2(x, arg1):
    m = x.sum() / x.size
    return m + arg1

df.groupby(by='户型')['价格'].transform(func2, arg1=10)

4 分组过滤

# df.groupby(by=[列名1, 列名2, ...]).filter(lambda x: 判断条件)
# 判断条件返回True或False
# 对每组的数据结果进行判断, 留下满足条件的组数据, 删除掉不满足条件的组数据

# 根据户型分组, 保留平均价格大于1w的组数据
# x是df分组对象, 获取df中的价格列求平均值
# 判断条件是每组的价格平均值和10000比较, 不是每条数据的价格和10000比较
df.groupby(by='户型').filter(lambda x:x['价格'].mean() > 10000)

# x是df分组对象后的价格列 -> s对象
s1 = df.groupby(by='户型')['价格'].filter(lambda x: x.mean() > 10000)
s1.index
df.loc[s1.index]

5 分箱

# 分箱->根据df中的某列值进行分组操作
# pd.cut(x=s对象, bins=, labels=, right=, include_lowest=)
# x:分箱的列
# bins: 分箱的箱数(组数), 接受整数, 或分箱规则列表->[0, 20, 40] 0~20 20~40 40以上
# labels: 分箱的名称, 不写也会有默认值 
# right: 分箱规则列表, 默认左开右闭 True, 左闭右开 False
# include_lowest: 是否包含第一组中的起始值, 默认False不包含
# 根据价格列对数据成3组
df['价格分组'] = pd.cut(x=df['价格'], bins=3)
df
# (0, 4500]->低 (4500, 8500]->中 (8500, 210000]->高
df['价格分组2'] = pd.cut(x=df['价格'], bins=[0, 4500, 8500, 210000], labels=['低', '中', '高'])
df

6 合并操作

6.1 纵向合并

类似于sql中的 union all 操作, 将多个df纵向连接到一起

# 导入模块
import pandas as pd
# 创建数据集
df1 = pd.DataFrame([[1, 2, 3], [1, 10, 20], [5, 6, 7], [3, 9, 0], [8, 0, 3]], columns=['x1', 'x2', 'x3'])
df2 = pd.DataFrame([[1, 2], [1, 10], [1, 3], [4, 6], [3, 9]], index=[0, 2, 4, 6, 8], columns=['x1', 'x4'])
print(df1)
print(df2)

# df1.append(df2), 根据列名相同进行追加, 列名不同用NaN值填充
# 在df1中追加df2
# 新df会保留各自df的索引值
df1.append(df2)
df1.append(df2).reset_index(drop=True)
# ignore_index=True:重置新df的索引值
df1.append(df2, ignore_index=True)

# pd.concat([df1, df2, df3, ...])
# 纵向合并多个df, 根据列名相同进行合并, 列名不同用NaN值填充
pd.concat([df1, df2], axis=0)
# 可以通过join参数, 设置保留df之间共有的数据, 默认是outer->保留所有数据, 类似于全连接
pd.concat([df1, df2], axis=0, join='inner', ignore_index=True)

6.2 横向合并

  • concat()

    # pd.concat([df1, df2, df3, ...], axis=1, ignore_index=, join=)
    # 将多个df根据行索引值进行合并, 索引值相同的合并, 不相同的用NaN值填充
    pd.concat([df1, df2], axis=1)
    # ignore_index=True: 重置列名
    pd.concat([df1, df2], axis=1, ignore_index=True)
    # join='inner': 保留共有的行数据
    pd.concat([df1, df2], axis=1, join='inner')
    
  • merge()

    # pd.merge(left=, right=, on=, left_on=, right_on=, how=)  等同于sql的join/left join...
    # df1.merge(df2, on=, how=)
    # 根据指定的列值进行横向合并
    # on=: 两个df相同的关联列名
    # left_on/right_on: 两个df中没有相同的关联列名
    # how: 合并方式, 默认是inner, 内连接
    # 默认是内连接, how='innner'
    df1.merge(df2, on='x1')
    # left_on/right_on: 两个df中没有相同的关联列名
    pd.merge(left=df1, right=df2, left_on='x3', right_on='x1')
    # 外连接, how='outer', 关联不上的用NaN值填充
    pd.merge(df1, df2, on='x1', how='outer')
    # 左连接, how='left'
    df1.merge(df2, on='x1', how='left')
    # 右连接, how='right'
    df1.merge(df2, on='x1', how='right')
    
    
  • join()

    # df1.join(df2, lsuffix=, rsuffix=, how=)
    # 根据两个df的行索引值进行横向合并, 索引值不同的用NaN值填充
    # lsuffix/rsuffix: 如果横向合并df中有重名的列名,需要通过此参数设置列名的后缀
    # how: 默认是left, 保留左df的所有数据; right, outer, inner
    df1.join(df2,lsuffix='_df1',rsuffix='_df2')
    df1.join(df2,lsuffix='_df1', rsuffix='_df2', how='inner')
    df1.join(df2,lsuffix='_df1', rsuffix='_df2', how='outer')
    

7 变形操作

7.1 转置

# 行变列, 列变行 -> 转置
# df.T
df1.T

7.2 stack和unstack

# 构造示例数据集
df3 = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=['store1', 'store2', 'store3'], index=['street1', 'street2'])
df3
# stack() -> 将df表格转换成series花括号
df3.stack()
type(df3.stack())
# unstack() -> 将series花括号转换成df表格
# 对多列进行分组后, 可以通过unstack进行转换
df3.stack().unstack()

df = pd.read_csv('data/LJdata.csv')
temp = df.groupby(by=['户型', '朝向'])['价格'].mean()
temp
temp.unstack()

7.3 melt

# df.melt(id_vars=, value_vars=, var_name=, value_name=) 将数据实现宽变长操作
# id_vars:不变形的列名列表,  如果不指定,除了value_vars指定的变形列, 其余列都不变形(会被删除)
# value_vars: 变形的列名列表, 将指定的列名值保存到新列中, 如果不指定,除了id_vars不变形的列, 其余列都变形
# var_name: 指定变形列名保存到新列中的列名
# value_name: 指定变形列的值保存到新列的列名

df4 = pd.read_csv('data/music.csv')
df4
df4.melt(
    id_vars=['artist', 'track'],
    value_vars=['wk1', 'wk2']
)

df4.melt(
    id_vars=['artist', 'track'],
    value_vars=['wk1', 'wk2'],
    var_name='week',  # 修改存储变形列名列的列名
    value_name='score'  # 修改存储变形列值列的列名
)

# 只指定不变形的列, 剩余列需要变形
df4.melt(id_vars=['artist', 'track'])
# 只指定变形的列, 剩余列会被删除
df4.melt(value_vars=['wk1', 'wk2'])

temp.unstack().reset_index().melt(id_vars=['户型'])

7.4 pivot_table

# 透视表操作 -> 类似于分组聚合
# pd.pivot_table(data=, index=,columns=,values=,aggfunc=,margins=)
# index:分组列名, 作为新df的行索引值
# columns:分组列名, 作为新df的列名
# values:聚合列名
# aggfunc:聚合函数名
# margins: 是否在最后一行或一列添加求和结果

data = pd.read_csv('data/uniqlo.csv')
data.head()
# 获取销售渠道为线下的所有数据
new_data = data.query('channel=="线下"')
new_data
# 制作透视表, 获取不同城市(city->行索引)不同商品(product->列名)的销售总金额(revenue)
pd.pivot_table(data=new_data, index='city', columns='product', values='revenue', aggfunc='sum', margins=True)

# 分组聚合后unstack 等同于 透视表操作
new_data.groupby(by=['city', 'product'])[['revenue']].sum().unstack()

# index, columns, values 可以指定多列
pd.pivot_table(data=data, index=['city', 'channel'], columns=['product'], values=['revenue', 'quant'], aggfunc='sum')

pd.pivot_table(data=data, index=['city'], columns=['channel','product'], values=['revenue', 'quant'], aggfunc='sum')

在这里插入图片描述

评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老爹@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值