本文目录
  1. Pandas数据分析
  2. 一、【了解】Pandas框架概述
    1. Pandas介绍
    2. 安装Pandas
    3. 【演示】Pandas初体验
    4. 小结
  3. 二、【熟悉】Pandas数据结构与数据类型
    1. 掌握内容
    2. Pandas数据结构和数据类型
    3. Series对象
      1. 创建Series对象
      2. Series对象属性
    4. DataFrame
      1. 创建DataFrame对象
      2. DataFrame对象属性
      3. DataFrame对象方法
      4. DataFrame索引的设置
    5. Pandas的数据类型
  4. 三、【掌握】Pandas基本数据操作
    1. 掌握内容
    2. 数据集
    3. 索引操作【重点】
      1. 直接使用行列索引(==先列后行==)
      2. 结合loc或者iloc使用索引(==先行后列==)
    4. 赋值操作【重点】
    5. 排序操作
      1. DataFrame排序
      2. Series排序
  5. 四、【理解】DataFrame运算
    1. 掌握内容
    2. 算术运算
    3. 逻辑运算符
      1. 逻辑运算符号
      2. 逻辑运算函数
    4. 统计运算【理解】
      1. describe
      2. 统计函数
      3. 累计统计函数【了解】
      4. apply自定义运算
  6. 五、【掌握】文件读取与存储
    1. 掌握内容
    2. CSV
      1. read_csv
      2. to_csv
    3. MySQL
    4. JSON
      1. read_json
      2. read_json案例
      3. to_json
      4. 案例
  7. 六、【熟悉】DataFrame数据的增删改查操作
    1. 掌握内容
    2. 增加列
    3. 删除与去重
    4. 修改DataFrame中的数据
    5. 查询dataFrame中的数据
  8. 七、【掌握】高级处理-缺失值处理
    1. 掌握内容
    2. 如何处理NAN
    3. 电影数据的缺失值处理
    4. 判断缺失值是否存在
    5. 存在缺失值nan,并且是np.nan
    6. 不是缺失值nan,有默认标记的
  9. 八、【熟悉】高级处理-数据合并
    1. 掌握内容
    2. pd.concat实现数据合并
    3. pd.merge
  10. 九、【理解】高级处理-数据分组
    1. 数据准备
    2. groupby分组聚合
  11. 十、【了解】高级处理-交叉表与透视表
    1. 交叉表与透视表有什么作用?
    2. 交叉表
    3. 透视表
    4. 案例分析
      1. 数据准备
      2. 查看效果
      3. 使用pivot_table(透视表)实现
    5. 总结
公告
淡泊明志,宁静致远
网站资讯
本站文章字数合计
322.7k
本站Hexo版本
6.1.0
本站Node版本
20.19.6
本站已运行时间
最后更新时间
本文目录
  1. Pandas数据分析
  2. 一、【了解】Pandas框架概述
    1. Pandas介绍
    2. 安装Pandas
    3. 【演示】Pandas初体验
    4. 小结
  3. 二、【熟悉】Pandas数据结构与数据类型
    1. 掌握内容
    2. Pandas数据结构和数据类型
    3. Series对象
      1. 创建Series对象
      2. Series对象属性
    4. DataFrame
      1. 创建DataFrame对象
      2. DataFrame对象属性
      3. DataFrame对象方法
      4. DataFrame索引的设置
    5. Pandas的数据类型
  4. 三、【掌握】Pandas基本数据操作
    1. 掌握内容
    2. 数据集
    3. 索引操作【重点】
      1. 直接使用行列索引(==先列后行==)
      2. 结合loc或者iloc使用索引(==先行后列==)
    4. 赋值操作【重点】
    5. 排序操作
      1. DataFrame排序
      2. Series排序
  5. 四、【理解】DataFrame运算
    1. 掌握内容
    2. 算术运算
    3. 逻辑运算符
      1. 逻辑运算符号
      2. 逻辑运算函数
    4. 统计运算【理解】
      1. describe
      2. 统计函数
      3. 累计统计函数【了解】
      4. apply自定义运算
  6. 五、【掌握】文件读取与存储
    1. 掌握内容
    2. CSV
      1. read_csv
      2. to_csv
    3. MySQL
    4. JSON
      1. read_json
      2. read_json案例
      3. to_json
      4. 案例
  7. 六、【熟悉】DataFrame数据的增删改查操作
    1. 掌握内容
    2. 增加列
    3. 删除与去重
    4. 修改DataFrame中的数据
    5. 查询dataFrame中的数据
  8. 七、【掌握】高级处理-缺失值处理
    1. 掌握内容
    2. 如何处理NAN
    3. 电影数据的缺失值处理
    4. 判断缺失值是否存在
    5. 存在缺失值nan,并且是np.nan
    6. 不是缺失值nan,有默认标记的
  9. 八、【熟悉】高级处理-数据合并
    1. 掌握内容
    2. pd.concat实现数据合并
    3. pd.merge
  10. 九、【理解】高级处理-数据分组
    1. 数据准备
    2. groupby分组聚合
  11. 十、【了解】高级处理-交叉表与透视表
    1. 交叉表与透视表有什么作用?
    2. 交叉表
    3. 透视表
    4. 案例分析
      1. 数据准备
      2. 查看效果
      3. 使用pivot_table(透视表)实现
    5. 总结
已阅读:%

分类: python | 标签: pandas

pandas

发表于: 2026-05-25 15:58:28 | 字数统计: 12.9k | 阅读时长预计: 64分钟

Pandas数据分析

一、【了解】Pandas框架概述

Pandas介绍

Python在数据处理上独步天下:代码灵活、开发快速;尤其是Python的Pandas包,无论是在数据分析领域、还是大数据开发场景中都具有显著的优势:

  • Pandas是Python的一个第三方包,也是商业和工程领域最流行的结构化数据工具集,用于数据清洗、处理以及分析
  • Pandas在数据处理上具有独特的优势:
    • 底层是基于Numpy构建的,所以运行速度特别的快
    • 有专门的处理缺失数据的API
    • 强大而灵活的分组、聚合、转换功能

image-20240831102204286

适用场景:

  • 数据量大到Excel严重卡顿,且又都是单机数据的时候,我们使用Pandas
    • Pandas用于处理单机数据(小数据集(相对于大数据来说))
  • 在大数据ETL数据仓库中,对数据进行清洗及处理的环节使用Pandas

安装Pandas

注意:Anaconda默认已经安装了Pandas以及Numpy等内容

打开cmd窗口,输入如下命令:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ pandas

image-20240831102459782

【演示】Pandas初体验

  • 1- 将资料中提供的数据集导入到data目录中

image-20240831102838020

  • 2- 创建python脚本, 导入pandas库
import pandas as pd
  • 3- 基于pandas加载数据
df = pd.read_csv('data/1960-2019全球GDP数据.csv', encoding='gbk')  

# 设置显示的最大行数和列数为None
pd.set_option(‘display.max_rows’, None)
pd.set_option(‘display.max_columns’, None)

# 恢复显示的最大行数到默认值
pd.reset_option(‘display.max_rows’)

# 恢复显示的最大列数到默认值
pd.reset_option(‘display.max_columns’)

# 恢复所有选项到默认值
pd.reset_option(‘all’)

  • 4- 基于pandas完成相关查询:
# 查询中国的GDP
china_gdp = df[df.country=='中国'] # df.country 选中名为country的列
china_gdp.head(10) # 显示前10条数据

运行结果:

image-20240831102944259

  • 5- 将year年份设置为索引
china_gdp = china_gdp.set_index('year')
china_gdp.head() # 默认显示前5条

image-20240831103707688

  • 6- 画出GDP逐年变化的曲线图
china_gdp.GDP.plot()

image-20240831103753090

使用同样的方法画出日本的GDP变化曲线,和中国的GDP变化曲线进行对比

jp_gdp = df[df.country=='日本'].set_index('year') # 按条件选取数据后,重设索引
jp_gdp.GDP.plot() 
china_gdp.GDP.plot()

image-20240831103842060

分别查询中国、美国、日本三国的GDP数据,并绘制GDP变化曲线、进行对比

china_gdp = df[df.country=='中国'].set_index('year')
us_gdp = df[df.country=='美国'].set_index('year')
jp_gdp = df[df.country=='日本'].set_index('year')
jp_gdp.GDP.plot()
china_gdp.GDP.plot()
us_gdp.GDP.plot()

image-20240831103923889

设置图例:

# 按条件选取数据
china_gdp = df[df.country=='中国'].set_index('year')
us_gdp = df[df.country=='美国'].set_index('year')
jp_gdp = df[df.country=='日本'].set_index('year')
# 出图并添加图例
jp_gdp.GDP.plot(legend=True)
china_gdp.GDP.plot(legend=True)
us_gdp.GDP.plot(legend=True)

image-20240831104008883

修改列名使图例显示为各国名称

# 按条件选取数据
china_gdp = df[df.country=='中国'].set_index('year')
us_gdp = df[df.country=='美国'].set_index('year')
jp_gdp = df[df.country=='日本'].set_index('year')
# 对指定的列修改列名
jp_gdp.rename(columns={'GDP':'japan'}, inplace=True)
china_gdp.rename(columns={'GDP':'china'}, inplace=True)
us_gdp.rename(columns={'GDP':'usa'}, inplace=True)
# 画图
jp_gdp.japan.plot(legend=True)
china_gdp.china.plot(legend=True)
us_gdp.usa.plot(legend=True)

image-20240831104043579

  • 7- 解决中文不能在图表中正常显示的问题

将列名改为中文,使图例显示为各国名称

# 按条件选取数据
china_gdp = df[df.country=='中国'].set_index('year')
us_gdp = df[df.country=='美国'].set_index('year')
jp_gdp = df[df.country=='日本'].set_index('year')
# 对指定的列修改列名
jp_gdp.rename(columns={'GDP':'日本'}, inplace=True)
china_gdp.rename(columns={'GDP':'中国'}, inplace=True)
us_gdp.rename(columns={'GDP':'美国'}, inplace=True)
# 画图
jp_gdp['日本'].plot(legend=True)
china_gdp['中国'].plot(legend=True)
us_gdp['美国'].plot(legend=True)

# 解决中文显示问题,下面的代码只需运行一次即可
import matplotlib as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

运行结果:

image-20240831104226246

小结

Python Pandas的作用:(清洗、处理、分析数据)

Pandas环境搭建:

  • 安装Anaconda,默认自带Python以及其他相关三方包
  • 使用默认的base虚拟环境启动JupyterNotebook

二、【熟悉】Pandas数据结构与数据类型

掌握内容

1- 创建
    pd.DataFrame(ndarray)
    
2- 方法
    head()
    tail()

3- 属性
    values
    T
    
4- 索引
    set_index()
    
5- 数据类型
    object、int、float、nan
    info()
    dtypes

Pandas数据结构和数据类型

image-20260417115734942

上图为上一节中读取并展示出来的数据,以此为例我们来讲解Pandas的核心概念,以及这些概念的层级关系:

  • DataFrame
    • Series
      • 数据列
        • 列名
        • 列值,具体的数据
    • 索引列
      • 索引名、索引值
      • 索引下标、行号

其中最核心的就是Pandas中的两个数据结构:DataFrame和Series

Series对象

Series也是Pandas中的最基本的数据结构对象,下文中简称s对象,是DataFrame的列对象,series本身也具有索引。

Series是一种类似于一维数组的对象,由下面两个部分组成:

image-20240831105304751

  • values:一组数据(numpy.ndarray类型)
  • index:相关的数据索引标签;如果没有为数据指定索引,于是会自动创建一个0到N-1(N为数据的长度)的整数型索引。

创建Series对象

  • 1- 导入pandas
import pandas as pd
import numpy as np
  • 2- 通过list列表来创建
# 使用默认自增索引
s2 = pd.Series([1, 2, 3])
print(s2)
# 使用自己指定的索引
# 注意:索引个数与值的个数必须完全一致
s3 = pd.Series(data=[11,22,33], index=["a","b","c"])
# s3 = pd.Series(data=[11,22,33], index=["a","b","c","d"])
# s3 = pd.Series(data=[11,22,33], index=["a","b"])
print(s3)
  • 3- 使用字典或元组创建series对象
#使用元组
tst = (1,2,3,4,5,6)
pd.Series(tst)

#使用字典:
dst = {'A':1,'B':2,'C':3,'D':4,'E':5,'F':6}
pd.Series(dst)
  • 4- 使用numpy创建series对象
pd.Series(np.arange(10))
# 运行结果
0    0
1    1
2    2
3    3
4    4
5    5
6    6
7    7
8    8
9    9
dtype: int64

课堂演示完整代码:

import pandas as pd

# 1----------- Series对象
# 1.1- 创建
# 通过list列表来创建 
# 查看源代码:Ctrl+Q Ctrl+鼠标左键
s1 = pd.Series(data=[11,22,33])
s1

# 使用自己指定的索引
# 注意:索引个数与值的个数必须完全一致
s2 = pd.Series(data=[11,22,33], index=["a","b","c"])
# s2 = pd.Series(data=[11,22,33], index=["a","b","c","d"])
# s2 = pd.Series(data=[11,22,33], index=["a","b"])
s2

# 通过元组或者字典来创建
s3 = pd.Series((11,22,33))
s3

my_dict = {"a":111,"b":6666,"c":6666}
# 字典中的key会作为行索引来使用;value作为字段值使用
s4 = pd.Series(my_dict)
s4

# 通过Numpy来创建
import numpy as np
arr = np.arange(start=1,stop=10,step=1) # 左闭右开的区间
print(arr)

s5 = pd.Series(arr)
s5

Series对象属性

构造一个series对象

s6 = pd.Series(data=[i*10 for i in range(5)], index=[i for i in "ABCDE"])
s6
# 返回结果如下
A    0
B    10
C    20
D    30
E    40
dtype: int64
  • 1- series对象常用属性
s6.index
  • 2- values
s6.values
  • 3- 也可以通过索引来获取数据
s6['C']

课堂演示完整代码:

import pandas as pd

# Series对象的属性
s6 = pd.Series(data=[i*10 for i in range(5)], index=[i for i in "ABCDE"])

print(f"Series的全部内容:\n{s6}")
print(f"获得索引:{s6.index}")
print(f"获得数据值:{s6.values}")
print(f"通过index索引获得数据值:{s6['C']}")

DataFrame

创建DataFrame对象

DataFrame是一个类似于二维数组或表格(如excel)的对象,既有行索引,又有列索引

  • 表示沿着行的方向(垂直向下)跨越,对每一列进行操作,结果是行数被修改了。==0轴,axis=0==,等价于 axis='index'
  • 表示沿着列的方向(水平向右)跨越,对每一行进行操作,结果是列数被修改了。==1轴,axis=1==,等价于 axis='columns'

image-20260525165333679

DataFrame的创建有很多种方式

读取文件数据返回df:在之前的学习中我们使用了pd.read_csv('csv格式数据文件路径')的方式获取了df对象

使用字典、列表、元组创建df:接下来就展示如何使用字典、列表+元组、numpy创建df对象


  • 1- 使用字典加列表创建df,使默认自增索引
df1_data = {
    '日期': ['2021-08-21', '2021-08-22', '2021-08-23'],
    '温度': [25, 26, 50],
    '湿度': [81, 50, 56] 
}
df1 = pd.DataFrame(data=df1_data)
df1

# 返回结果如下
        日期    温度    湿度
0    2021-08-21    25    81
1    2021-08-22    26    50
2    2021-08-23    50    56
  • 2- 使用列表加元组创建df,并自定义索引
df2_data = [
    ('2021-08-21', 25, 81),
    ('2021-08-22', 26, 50),
    ('2021-08-23', 27, 56)
]

df2 = pd.DataFrame(
    data=df2_data, 
    columns=['日期', '温度', '湿度'],
    index = ['row_1','row_2','row_3'] # 手动指定索引
)
df2

# 返回结果如下
            日期    温度    湿度
row_1    2021-08-21    25    81
row_2    2021-08-22    26    50
row_3    2021-08-23    27    56
  • 3- 使用numpy创建df

通过已有数据创建

pd.DataFrame(np.random.randint(40, 100, (10, 5)))

创建学生成绩表

# 生成10名同学,5门功课的数据
score = np.random.randint(40, 100, (10, 5))

# 结果
array([[92, 55, 78, 50, 50],
       [71, 76, 50, 48, 96],
       [45, 84, 78, 51, 68],
       [81, 91, 56, 54, 76],
       [86, 66, 77, 67, 95],
       [46, 86, 56, 61, 99],
       [46, 95, 44, 46, 56],
       [80, 50, 45, 65, 57],
       [41, 93, 90, 41, 97],
       [65, 83, 57, 57, 40]])

但是这样的数据形式很难看到存储的是什么的样的数据,可读性比较差!

问题:如何让数据更有意义的显示?

# 使用Pandas中的数据结构
score_df = pd.DataFrame(score)

image-20240831110743788

给分数数据增加行列索引,显示效果更佳

效果:

image-20240831110830968

增加行、列索引

# 构造列索引序列
subjects = ["语文", "数学", "英语", "政治", "体育"]

# 构造行索引序列
stu = ['同学' + str(i) for i in range(score_df.shape[0])]

# 添加索引
data = pd.DataFrame(score, columns=subjects, index=stu)

DataFrame对象属性

属性

  • 1- shape属性
data.shape

# 结果
(10, 5)
  • 2- index属性

DataFrame的行索引列表

data.index

# 结果
Index(['同学0', '同学1', '同学2', '同学3', '同学4', '同学5', '同学6', '同学7', '同学8', '同学9'], dtype='object')
  • 3- columns
data.columns

# 结果
Index(['语文', '数学', '英语', '政治', '体育'], dtype='object')
  • 4- values

直接获取其中array的值

data.values

array([[92, 55, 78, 50, 50],
       [71, 76, 50, 48, 96],
       [45, 84, 78, 51, 68],
       [81, 91, 56, 54, 76],
       [86, 66, 77, 67, 95],
       [46, 86, 56, 61, 99],
       [46, 95, 44, 46, 56],
       [80, 50, 45, 65, 57],
       [41, 93, 90, 41, 97],
       [65, 83, 57, 57, 40]])
  • 5- T

转置:行转列

data.T

结果

image-20240831111307825

DataFrame对象方法

1- head(n)

显示前n行内容

data.head(5)

image-20240831111502466

2- tail(n)

显示后n行内容

如果不补充参数,默认5行。填入参数n则显示后n行

data.tail(5)

….其他的方法自己去测试…

DataFrame索引的设置

image-20240831111650351

  • 1- 修改行列索引
stu = ["学生_" + str(i) for i in range(score_df.shape[0])]

# 必须整体全部修改
data.index = stu

注意:以下修改方式是错误的

# 错误修改方式
data.index[3] = '学生_3'

可能遇到的错误:

1745315629151

原因: DataFrame的索引修改只能整体进行修改,不能修改部分。但是我们可以通过rename重命名的方式修改部分索引,例如:
data.rename(index={'Avatar':'avatar'},inplace=True)
代码表示的意思是将行索引的旧名称Avatar改成新名称avatar
  • 2- 重设索引
    • reset_index(drop=False)
      • 设置新的下标索引
      • drop:默认为False,不删除原来索引,如果为True,删除原来的索引值
# 重置索引,drop=False
data.reset_index()

image-20240831111957305

# 重置索引,drop=True
data.reset_index(drop=True)
  • 3- 以某列值设置为新的索引
    • set_index(keys, drop=True)
      • keys : 列索引名成或者列索引名称的列表
      • drop : boolean, default True.当做新的索引,删除原来的列

设置新索引案例

第一步:创建

df = pd.DataFrame({'month': [1, 4, 7, 10],
                    'year': [2012, 2014, 2013, 2014],
                    'sale':[55, 40, 84, 31]})

   month  sale  year
0  1      55    2012
1  4      40    2014
2  7      84    2013
3  10     31    2014

第二步:以月份设置新的索引

df.set_index('month')
       sale  year
month
1      55    2012
4      40    2014
7      84    2013
10     31    2014

第三步:设置多个索引,以年和月份

df = df.set_index(['year', 'month'])
df
            sale
year  month
2012  1     55
2014  4     40
2013  7     84
2014  10    31

Pandas的数据类型

df或s对象中具体每一个值的数据类型有很多,如下表所示

Pandas数据类型说明对应的Python类型
object==字符串类型==string
int整数类型int
float浮点数类型float
datetime日期时间类型datetime包中的datetime类型
timedelta时间差类型datetime包中的timedelta类型
category分类类型无原生类型,可以自定义
bool布尔类型bool(True,False)
nan空值类型None
  • 可以通过下列API查看s对象或df对象中数据的类型
s1.dtypes
df1.dtypes
df1.info()
  • c

    • datetime类型
    import pandas as pd
    
    # 创建一个datetime类型的Series
    dates = pd.to_datetime(['2024-09-01', '2024-09-02', '2024-09-03'])
    print(dates)
    
    • timedelta类型
    import pandas as pd
    
    # 计算两个日期之间的差值
    start_date = pd.to_datetime('2024-09-01')
    end_date = pd.to_datetime('2024-09-05')
    delta = end_date - start_date
    print(delta)
    
    • category类型

    类型用于表示分类数据,通常用于有限集合中的数据类型,例如性别、颜色、产品类型等。这种类型的优点在于占用更少的内存,并且对分类数据的操作更快。

    import pandas as pd
    
    # 创建一个category类型的Series
    categories = pd.Series(['apple', 'banana', 'apple', 'orange'], dtype='category')
    print(categories)
    

三、【掌握】Pandas基本数据操作

掌握内容

1- 索引操作
    loc[行索引名称开始:行索引名称结束, 列索引名称开始:列索引名称结束],注意左右都是闭区间
    iloc[行索引下标开始:行索引下标结束, 列索引下标开始:列索引下标结束],注意左闭右开

2- 赋值操作
    DataFrame对象['字段名称'] = 字段值

3- 排序操作
    sort_index()

数据集

为了更好的理解这些基本操作,我们将读取一个真实的股票数据。关于文件操作,后面在介绍,这里只先用一下API

# 读取文件
data = pd.read_csv("./data/stock_day.csv")

# 删除一些列,让数据更简单些,再去做后面的操作
data = data.drop(["ma5","ma10","ma20","v_ma5","v_ma10","v_ma20"], axis=1)

image-20240831113957256

索引操作【重点】

直接使用行列索引(==先列后行==)

获取’2018-02-27’这天的’open’的结果

# 第1种:通过行列索引值取内容
# 注意:必须是先写列,再写行
df2["volume"]["2018-02-22"]

# 其他错误的写法
# 行索引放错位置了
# df2["2018-02-22"]["volume"]

# 该方式不支持索引下标
df2[1][1]

结合loc或者iloc使用索引(==先行后列==)

获取从’2018-02-27’:’2018-02-22’,’open’的结果

# 第2种:通过loc和行列索引值取内容
# 语法总结:[行索引开始名称:行索引结束名称, 列索引开始名称:列索引结束名称],注意左右都是闭区间

df2.loc["2018-02-22","volume"]

df2.loc["2018-02-26":"2018-02-22","volume"]

df2.loc["2018-02-26":"2018-02-23","close":"low"]



# 第3种:通过iloc和行列索引下标取内容
# 语法总结:[行索引开始下标:行索引结束下标, 列索引开始下标:列索引结束下标],注意左闭右开

df2.iloc[2,1]   # 23.37

df2.iloc[2,1:3] # 23.37  22.82

df2.iloc[1:3, 1:4]

赋值操作【重点】

对DataFrame当中的close列进行重新赋值为1

# 推荐。直接修改原来的值
data['close'] = 1

# 或者
data.close = 1

排序操作

排序有两种形式,一种对于索引进行排序,一种对于内容进行排序

DataFrame排序

  • 使用df.sort_values(by=, ascending=)
    • 单个键或者多个键进行排序,
    • 参数:
      • by:指定排序参考的键
      • ascending:默认升序
        • ascending=False:降序
        • ascending=True:升序
# 按照开盘价大小进行排序 , 使用ascending指定按照大小排序
data.sort_values(by="open", ascending=True).head()

image-20240831115123196

# 按照多个键进行排序
data.sort_values(by=['open', 'high'])

image-20240831115137667

  • 使用df.sort_index给索引进行排序

这个股票的日期索引原来是从大到小,现在重新排序,从小到大

# 对索引进行排序
data.sort_index()

image-20240831115237626

Series排序

  • 使用series.sort_values(ascending=True)进行排序

series排序时,只有一列,不需要参数

data['p_change'].sort_values(ascending=True).head()

2015-09-01   -10.03
2015-09-14   -10.02
2016-01-11   -10.02
2015-07-15   -10.02
2015-08-26   -10.01
Name: p_change, dtype: float64
  • 使用series.sort_index()进行排序

与df一致

# 对索引进行排序
data['p_change'].sort_index().head()

2015-03-02    2.62
2015-03-03    1.44
2015-03-04    1.57
2015-03-05    2.02
2015-03-06    8.51
Name: p_change, dtype: float64

四、【理解】DataFrame运算

掌握内容

describe():对数据的整体情况进行了解
apply():数据自定义处理函数

算术运算

  • add(other)

比如进行数学运算加上具体的一个数字

# ---------------- 算术运算 ----------------
df1 = df.add(100)           # DF中所有单元格的数字全部都加上指定的参数值
df1 = df["open"].add(1000)  # 从DF中取出一列进行计算
df1
  • sub(other)

比如进行数学运算减去具体的一个数字

df2 = df["open"].sub(1000)  # 减法
df2 = df["open"].div(100)  # 除法
df2 = df["open"].mul(100)  # 乘法

# 同时支持算术运算的符号
df2 = df["open"] * 10000  # 乘法
df2 = df["open"] + 10000  # 加法
df2

逻辑运算符

总结:
    1- 逻辑运算中不能使用单词and、or、not,必须使用对应的符号& | ~
    2- 每个比较运算符表达式必须使用小括号包起来

逻辑运算符号

  • 例如筛选data[“open”] > 23的日期数据
    • data[“open”] > 23返回逻辑结果
# ---------------- 逻辑运算 ----------------
# 数据大小判断
df["open"]>22

# 将判断语句作为过滤条件,对数据进行过滤。True的保留;False的不要
# 类似SQL中的写法:select * from df where open>22
df[df["open"]>22]

image-20240831115813316

  • 完成多个逻辑判断
# 能够写多个逻辑表达式
# 类似SQL中的写法:select * from df where open>22 and close<=22

# 下面是错误的写法,会报错:The truth value of a Series is ambiguous
# df[df["open"]>22 and df["close"]<=22]

"""
    注意事项:如下两个是必须要满足
        1- 不能使用逻辑运算的单词and、or、not,需要改成对应的符号&、|、~
        2- 每个比较运算表达式要用小括号包起来
"""
# and
# 正确写法
df[(df["open"]>22) & (df["close"]<=22)]

# or
# 错误写法
# df[(df["open"]>22) or (df["close"]<=22)]
# 正确的写法
df[(df["open"]>22) | (df["close"]<=22)]

# not
# 错误写法
# df[not df["open"]>22]
# 正确的写法
df[~(df["open"]>22)]

image-20240831115819104

逻辑运算函数

  • query(expr)
    • expr:查询字符串

通过query使得刚才的过程更加方便简单

# 简单的形式,使用query函数
df.query("open>22 and close<=22 and low>=21")
df.query("open>22 or close<=22")
df.query("not open>22")
df.query("open in (23.53,22.80)")
# 注意:判断是否相等需要使用两个等号
df.query("open==23.53")
  • isin(values)

例如判断’open’是否为23.53和23.85

# 可以指定值进行一个判断,从而进行筛选操作
data[data["open"].isin([23.53, 23.85])]

统计运算【理解】

describe

综合分析: 能够直接得出很多统计结果,count, mean, std, min, max

# 计算平均值、标准差、最大值、最小值
data.describe()

image-20240831123336370

image-20250713112353100

统计函数

Numpy当中已经详细介绍,在这里我们演示min(最小值), max(最大值), mean(平均值), median(中位数), var(方差), std(标准差),mode(众数)结果:

countNumber of non-NA observations
sumSum of values
meanMean of values
medianArithmetic median of values
minMinimum
maxMaximum
modeMode(众数)
absAbsolute Value
prodProduct of values(乘积)
stdBessel-corrected sample standard deviation
varUnbiased variance
idxmaxcompute the index labels with the maximum
idxmincompute the index labels with the minimum

对于单个函数去进行统计的时候,坐标轴还是按照默认列“columns” (axis=0, default),如果要对行“index” 需要指定(axis=1)

  • max()、min()
# 使用统计函数
data.max(0)

open                   34.99
high                   36.35
close                  35.21
low                    34.01
volume             501915.41
price_change            3.03
p_change               10.03
turnover               12.56
my_price_change         3.41
dtype: float64
  • std()、var()
# 方差
data.var(0)

open               1.545255e+01
high               1.662665e+01
close              1.554572e+01
low                1.437902e+01
volume             5.458124e+09
price_change       8.072595e-01
p_change           1.664394e+01
turnover           4.323800e+00
my_price_change    6.409037e-01
dtype: float64

# 标准差
data.std(0)

open                   3.930973
high                   4.077578
close                  3.942806
low                    3.791968
volume             73879.119354
price_change           0.898476
p_change               4.079698
turnover               2.079375
my_price_change        0.800565
dtype: float64
  • median():中位数

中位数为将数据从小到大排列,在最中间的那个数为中位数。如果没有中间数,取中间两个数的平均值。

df = pd.DataFrame({'COL1' : [2,3,4,5,4,2], 'COL2' : [0,1,2,3,4,2]})

df.median()

COL1    3.5
COL2    2.0
dtype: float64
  • idxmax()、idxmin()
# 求出最大值的位置
data.idxmax(axis=0)

open               2015-06-15
high               2015-06-10
close              2015-06-12
low                2015-06-12
volume             2017-10-26
price_change       2015-06-09
p_change           2015-08-28
turnover           2017-10-26
my_price_change    2015-07-10
dtype: object


# 求出最小值的位置
data.idxmin(axis=0)

open               2015-03-02
high               2015-03-02
close              2015-09-02
low                2015-03-02
volume             2016-07-06
price_change       2015-06-15
p_change           2015-09-01
turnover           2016-07-06
my_price_change    2015-06-15
dtype: object

累计统计函数【了解】

函数作用
cumsum计算前1/2/3/…/n个数的和
cummax计算前1/2/3/…/n个数的最大值
cummin计算前1/2/3/…/n个数的最小值
cumprod计算前1/2/3/…/n个数的积

那么这些累计统计函数怎么用?

image-20240831123744166

以上这些函数可以对series和dataframe操作

这里我们按照时间的从前往后来进行累计

  • 排序
# 排序之后,进行累计求和
data = data.sort_index()
  • 对p_change进行求和
stock_rise = data['p_change']
# plot方法集成了前面直方图、条形图、饼图、折线图
stock_rise.cumsum()

那么如何让这个连续求和的结果更好的显示呢?

image-20240831124825773

如果要使用plot函数,需要导入matplotlib.

import matplotlib.pyplot as plt
# plot显示图形
stock_rise.cumsum().plot()
# 需要调用show,才能显示出结果
plt.show()

apply自定义运算

  • apply(func, axis=0)
    • func:自定义函数
    • axis=0:默认是列,axis=1为行进行运算
  • 定义一个对列,最大值-最小值的函数
data[['open', 'close']].apply(lambda x: x.max() - x.min(), axis=0)

五、【掌握】文件读取与存储

掌握内容

read_csv()
read_sql()
read_json():推荐参数组合orient="records",lines=True

to_csv()
to_sql()
to_json():推荐参数组合orient="records",lines=True

我们的数据大部分存在于文件当中,所以pandas会支持复杂的IO操作,pandas的API支持众多的文件格式,如CSV、SQL、XLS、JSON、HDF5。

注:最常用的sql和CSV文件

image-20240831125310359

CSV

read_csv

  • pandas.read_csv(filepath_or_buffer, sep =’,’, usecols )
    • filepath_or_buffer:文件路径
    • sep :分隔符,默认用”,”隔开
    • usecols:指定读取的列名,列表形式
  • 举例:读取之前的股票的数据
# 读取文件,并且指定只获取'open', 'close'指标
data = pd.read_csv("./data/stock_day.csv", usecols=['open', 'close'])

to_csv

  • DataFrame.to_csv(path_or_buf=None, sep=’, ’, columns=None, header=True, index=True, mode=’w’, encoding=None)
    • path_or_buf :文件路径
    • sep :分隔符,默认用”,”隔开
    • columns :选择需要的列索引
    • header : 是否要将字段名称输出到文件中作为第一行。推荐使用True
    • index:是否写进行索引,是否写进列索引值
    • mode:’w’:覆盖写, ‘a’ 追加
    • encoding:输出的文件编码方式。推荐使用UTF-8
  • 举例:保存读取出来的股票数据
    • 保存’open’列的数据,然后读取查看结果
"""
    参数解释:
        filepath_or_buffer:文件路径
        sep:字段值之间的分隔符
        encoding:文件的编码方式
        usecols:将哪些字段读取出来
"""
# 读取
df1 = pd.read_csv(filepath_or_buffer="data/stock_day.csv",sep=",",encoding="UTF-8")
df1


# 指定将哪些字段读取出来
df2 = pd.read_csv(filepath_or_buffer="data/stock_day.csv",sep=",",encoding="UTF-8",usecols=["open","high"])
df2

会发现将索引存入到文件当中,变成单独的一列数据。如果需要删除,可以指定index参数,删除原来的文件,重新保存一次。

"""
    参数解释
        path_or_buf:文件的写出路径
        sep:字段值之间的分隔符
        mode:写出模式。w覆盖写,a追加写
        encoding:文件的编码方式
        columns:要将哪些字段写出到文件中
        header:是否在文件的第一行记录字段名称。推荐设置为True
        index:是否将索引列的内容写出到文件
"""
# 将数据写出成csv文件
df1.to_csv(path_or_buf="data/stock_to_csv.csv",sep="\t",mode="w",encoding="UTF-8")

df1.to_csv(
    path_or_buf="data/stock_to_csv_2.csv",
    sep="\t",
    mode="w",
    encoding="UTF-8",
    columns=["open","close","high"],
    header=False,
    index=False
)

MySQL

以MySQL数据库为例,此时默认你已经安装好了MySQL数据库。如果想利用pandas和MySQL数据库进行交互,需要先安装与数据库交互所需要的python包

pip install pymysql==1.0.2 -i https://pypi.tuna.tsinghua.edu.cn/simple/


# 如果后边的代码运行提示找不到sqlalchemy的包,和pymysql一样进行安装即可
pip install sqlalchemy==2.0.30 -i https://pypi.tuna.tsinghua.edu.cn/simple/

image-20220125205916505

  • 准备要写入数据库的数据
import pandas as pd 
"""
    index_col:指定使用文件中哪个索引的字段作为DataFrame的索引
"""
# 准备数据
df2 = pd.read_csv("data/csv示例文件.csv",sep=",",encoding="GBK",index_col=[0])
df2

image-20220123165416808

  • 创建数据库操作引擎对象并指定数据库
# 创建数据库连接
from sqlalchemy import create_engine
# 格式    数据库产品类型+开源库://用户名:密码@ip地址:端口号/数据库名称?其他参数设置
engine = create_engine("mysql+pymysql://root:root@127.0.0.1:3306/db4?charset=utf8")
  • 将数据写入MySQL数据库
# 写入到数据库
"""
    参数解释:
        name:要写入的表名。如果不存在,自动创建
        con:connection,数据库连接
        if_exists:如果表或者数据已经存在的处理方式
            append:追加写
            replace:覆盖写
            fail:如果表存在,直接报错
"""
# df2.to_sql(name="sql_test",con=engine,if_exists="replace",index=False)

# df2.to_sql(name="sql_test",con=engine,if_exists="append",index=False)

df2.to_sql(name="sql_test",con=engine,if_exists="fail",index=False)
  • 此时我们就可以在本地test库的test_pdtosql表中看到写入的数据

    image-20220123165745328

  • 从数据库中加载数据:

    • 读取整张表, 返回dataFrame
    # 读取数据表
    df3 = pd.read_sql(sql="sql_test",con=engine)
    
    • 使用SQL语句获取数据,返回dataframe
    # 传入sql语句,传入数据库连接引擎对象
    df4 = pd.read_sql(sql="select * from sql_test where name='赵金龙' ",con=engine)
    

可能出现的问题:

image-20220125211715019

说明: 
    sqlalchemy 库版本过低导致的

解决方案:
    先删除原有版本: 
        pip uninstall sqlalchemy
    
    重新安装:
        pip install sqlalchemy==2.0.30
sqlalchemy官网:https://www.sqlalchemy.org/
数据库连接如何写:https://docs.sqlalchemy.org/en/20/dialects/mysql.html#module-sqlalchemy.dialects.mysql.pymysql

JSON

JSON在线解析网站:https://www.sojson.com/

JSON只能使用双引号。而Python中的字典单引号、双引号都行

JSON是我们常用的一种数据交换格式,前面在前后端的交互经常用到,也会在存储的时候选择这种格式。所以我们需要知道Pandas如何进行读取和存储JSON格式。

read_json

  • pandas.read_json(path_or_buf=None, orient=None, typ=’frame’, lines=False)

    • 将JSON格式转换成默认的Pandas DataFrame格式

    • orient : string,Indication of expected JSON string format.

      • split : JSON内容包含索引、值、列名

      • records: ==推荐使用==。每条数据形成一个字典

      • index: 每条数据形成一个字典。并且索引作为key,列和值形成的字典作为value

      • columns: key是列名,value是索引和值形成的字典

      • values: 只输出数据值,不带索引和列名

    • lines : ==推荐使用True==如果为 True,则每一行是一个独立的 JSON 对象

    • typ : 指定转换成的对象类型series或者dataframe

read_json案例

  • 数据介绍

这里使用一个新闻标题数据集,格式为json。存储格式为:

{"article_link": "https://www.huffingtonpost.com/entry/versace-black-code_us_5861fbefe4b0de3a08f600d5", "headline": "former versace store clerk sues over secret 'black code' for minority shoppers", "is_sarcastic": 0}
{"article_link": "https://www.huffingtonpost.com/entry/roseanne-revival-review_us_5ab3a497e4b054d118e04365", "headline": "the 'roseanne' revival catches up to our thorny political mood, for better and worse", "is_sarcastic": 0}
  • 读取

orient指定存储的json格式,lines指定按照行去变成一个样本

"""
    参数解释:
        path_or_buf:文件路径
        orient:JSON格式。推荐使用records,那么JSON的格式就是键值对的形式
        lines:数据中每一行试一个单独的JSON
"""
json_read = pd.read_json("./data/Sarcasm_Headlines_Dataset.json", orient="records", lines=True)

结果:

image-20240831130046220

to_json

  • DataFrame.to_json(path_or_buf=None,orient=None,lines=False)
    • 将Pandas 对象存储为json格式
    • path_or_buf=None:文件地址
    • orient:存储的json形式,{‘split’,’records’,’index’,’columns’,’values’}==推荐使用records==
    • lines:一个对象存储为一行==推荐使用True==

案例

  • 存储文件
json_read.to_json("./data/test.json", orient='records')

结果

[{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/versace-black-code_us_5861fbefe4b0de3a08f600d5","headline":"former versace store clerk sues over secret 'black code' for minority shoppers","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/roseanne-revival-review_us_5ab3a497e4b054d118e04365","headline":"the 'roseanne' revival catches up to our thorny political mood, for better and worse","is_sarcastic":0},{"article_link":"https:\/\/local.theonion.com\/mom-starting-to-fear-son-s-web-series-closest-thing-she-1819576697","headline":"mom starting to fear son's web series closest thing she will have to grandchild","is_sarcastic":1},{"article_link":"https:\/\/politics.theonion.com\/boehner-just-wants-wife-to-listen-not-come-up-with-alt-1819574302","headline":"boehner just wants wife to listen, not come up with alternative debt-reduction ideas","is_sarcastic":1},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/jk-rowling-wishes-snape-happy-birthday_us_569117c4e4b0cad15e64fdcb","headline":"j.k. rowling wishes snape happy birthday in the most magical way","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/advancing-the-worlds-women_b_6810038.html","headline":"advancing the world's women","is_sarcastic":0},....]
  • 修改lines参数为True
json_read.to_json("./data/test.json", orient='records', lines=True)

结果

{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/versace-black-code_us_5861fbefe4b0de3a08f600d5","headline":"former versace store clerk sues over secret 'black code' for minority shoppers","is_sarcastic":0}
{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/roseanne-revival-review_us_5ab3a497e4b054d118e04365","headline":"the 'roseanne' revival catches up to our thorny political mood, for better and worse","is_sarcastic":0}
{"article_link":"https:\/\/local.theonion.com\/mom-starting-to-fear-son-s-web-series-closest-thing-she-1819576697","headline":"mom starting to fear son's web series closest thing she will have to grandchild","is_sarcastic":1}
{"article_link":"https:\/\/politics.theonion.com\/boehner-just-wants-wife-to-listen-not-come-up-with-alt-1819574302","headline":"boehner just wants wife to listen, not come up with alternative debt-reduction ideas","is_sarcastic":1}
{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/jk-rowling-wishes-snape-happy-birthday_us_569117c4e4b0cad15e64fdcb","headline":"j.k. rowling wishes snape happy birthday in the most magical way","is_sarcastic":0}...
  • 其他参数值演示
json_read.to_json(path_or_buf="data/copy2_json.json",orient="records",lines=False)
json_read.to_json(path_or_buf="data/copy3_json.json",orient="split",lines=False)
json_read.to_json(path_or_buf="data/copy4_json.json",orient="index",lines=False)

六、【熟悉】DataFrame数据的增删改查操作

掌握内容

1- 增加新字段
DataFrame对象["新字段名称"] = 字段值

2- 删除字段
drop()

3- 去重
unique()

4- 修改
DataFrame对象["字段名称"] = 新的字段值
  • 导包并加载数据:
import pandas as pd

df = pd.read_csv('data/1960-2019全球GDP数据.csv', encoding='gbk')  
df2 = df.head()

增加列

  • 方式一: 通过直接赋值的方式添加新列【掌握】
# 拷贝一份df
df3 = df2.copy()

# 一列数据都是固定值
df3['new col 1'] = 33

# 新增列数据数量必须和行数相等
df3['new col 2'] = [1, 2, 3, 4, 5]
df3['new col 3'] = df3.year * 2

# 分别查看增加数据列之后的df和原df
df3 
df2
  • 方式二: df.assign函数添加列
# 1. 新列名=单个数据或一组数据,一组数据的数量必须和df的行数相同
df2.assign(new0=66)
# df2.assign(new1=[1, 2, 3, 4]) # 报错
df2.assign(new1=[1, 2, 3, 4, 5])

# 2.1 新列名=Series对象,该s对象的索引和df索引一致
s = pd.Series([1, 2, 3, 4, 5]) 
df2.assign(new2=s)

# 2.2 新列名=Series对象
df2.assign(new3=df2.year+df2.GDP)

# 3. 新列名=自定义函数名
# 该自定义函数必须接收df作为参数
# 该自定义函数可以返回:
# 3.1.单个数据 
# 3.2.一组数量和df的行数相同的数据 
# 3.3.和df索引相同的Series对象
def foo(df):
    # 函数必须接收一个参数,该参数就是被传入的df对象
    print('='*10)
    print(df)
    print('='*5 + '上面输出的是传入的df')
    ret = df.index.values
    # 可以返回一个变量
    # return 'hahah'
    # 也可以返回一组变量
    return ret 
df2.assign(new4=foo)

解析:当我们使用函数的方式向df对象添加新列时,foo函数要求必须有一个参数,这个参数来自于调用assign的df对象,如上图所示
当我们给foo(df)定义一个df参数时,当assign方法开始执行,则系统会自动将df2对象作为参数传递给foo函数中的df参数
  • df.assign函数可以同时添加多列
# assign特殊
def fn1(my_df):
    return 22

def fn2(my_df):
    return my_df.GDP/1000000+my_df.year

df_5 = df_4.assign(
    new1=100,
    new2=[11,22,33,44,55],
    new3=df_4.year*100,
    new4=fn1,
    new5=fn2
)
df_5

删除与去重

  • 1- df.drop删除行数据
df3.drop([0]) # 默认删除行
df3.drop([0, 2, 4]) # 可以删除多行
df3.GDP.drop([0, 2]) # 对series对象按索引删除
  • 2- df.drop删除列数据【掌握】
    • df.drop默认删除指定索引值的行;如果添加参数axis=1,则删除指定列名的列
df3.drop(['new col 3'], axis=1)
  • 3- 使用del删除指定的列
    • 注意区别:
      • del是直接永久删除原df中的列【慎重使用】
      • drop是返回删除后的df或seires,原df或seires没有被修改
del df3['new col 3']
df3
# 重复运行本段代码将会报错,因为df3中的指定列在第一次运行时就被删除了
  • 4- Dataframe数据去重
# 添加一部分重复的数据
df6 = pd.concat([df5, df5], axis=0).reset_index(drop=True)

# keep:保留重复数据中的第几条。first表示第一条;last表示最后一条
# df7 = df6.drop_duplicates(keep="first")
df7 = df6.drop_duplicates(keep="last")
df7

image-20220123175505374

  • 5- series去重
# Series数据去重
from pandas import Series
s2:Series = df6.country
s3 = s2.drop_duplicates()  # 返回结果数据类型 是 Series对象
s3

arr1 = s2.unique()  # 返回结果数据类型 是 Numpy中的ndarray
arr1

修改DataFrame中的数据

  • 1- df.assign替换列
df = pd.read_csv('data/1960-2019全球GDP数据.csv', encoding='GBK')  
df5 = df.head()
df5
df5.assign(GDP=66) # 可以接收单变量或列表、数组
df5  # 此时原始的df5不会发生改变
  • 2- 直接对原始的DF进行赋值修改处理
df = pd.read_csv('../数据集/1960-2019全球GDP数据.csv', encoding='gbk', )  
df5 = df.head()
df5
df5['GDP'] = [5, 4, 3, 2, 1]
df5  # 此时原始的df5会发生改变
  • 3- replace函数替换数据
# replace替换函数:DF、Series对象都有该方法。只能够整体匹配然后替换,不能局部替换
df10 = df.head().copy()


df11 = df10.replace(to_replace="日本",value="扶桑")
df11

# 只能够整体匹配然后替换,不能局部替换
s4 = df10.year.replace(to_replace=1960,value=196666)
# s4 = df10.year.replace(to_replace=196,value=1999999)
# s4 = df10.country.replace(to_replace="日",value="sun")
s4

查询dataFrame中的数据

  • 1- 从前从后取多行数据

    • head()
    # 导包 
    import pandas as pd
    # 加载csv数据,指定gbk编码格式来读取文件,返回df
    df = pd.read_csv('../数据集/1960-2019全球GDP数据.csv', encoding='gbk') 
    
    # 默认取前5行数据
    df.head()
    df.head(10) # 取前10行
    
    • tail()
    # 默认取后5行数据
    df.tail()
    df2 = df.tail(15) # 倒数15行
    df2
    
  • 2- 获取一列或多列数据

    • 获取一列数据df[col_name]等同于df.col_name
    # 下面两种方式获得的结果类型都是Series对象
    df2['country']
    df2.country
    # 注意!如果列名字符串中间有空格的,只能使用df['country']这种形式
    
    • 获取多列数据df[[col_name1,col_name2,...]]
    df2[['country', 'GDP']] # 返回新的df
    
  • 3- 索引下标切片取行

    • df[start:stop:step]:

    df[start:stop:step] == df[起始行下标:结束行下标:步长] , 遵循顾头不顾尾原则(包含起始行,不包含结束行),步长默认为1

    df4 = df.head(10) # 取原df前10行数据作为df4,默认自增索引由0到9
    df4[0:3] # 取前3行
    df4[:5:2] # 取前5行,步长为2
    df4[1::3] # 取第2行到最后所有行,步长为3
    
  • 4- 查询函数获取子集: df.query()

    • df.query(判断表达式)可以依据判断表达式返回的符合条件的df子集
    • df[布尔值向量]效果相同
    • 特别注意df.query()中传入的字符串格式
    • 示例:
    df3.query('country=="帕劳"')
    df3[df3['country']=='帕劳']
    
    • 查询中国, 美国 日本 三国 2015年至2019年的数据
    df.query('country=="中国" or country=="日本" or country=="美国"').query('year in ["2015", "2016", "2017", "2018", "2019"]')
    
    df.query('(country=="中国" or country=="日本" or country=="美国") and year in ["2015", "2016", "2017", "2018", "2019"]')
    
  • 5- 排序函数

    • sort_values函数: 按照指定的一列或多列的值进行排序
    # 按GDP列的数值由小到大进行排序
    df2.sort_values(['GDP'])
    # 按GDP列的数值由大到小进行排序
    df2.sort_values(['GDP'], ascending=False) # 倒序, ascending默认为True
    # 先对year年份进行由小到大排序,再对GDP由小到大排序
    df2.sort_values(['year', 'GDP'])
    
    • rank函数【了解】:
    • rank函数用法:DataFrame.rank()Series.rank()
    • rank函数返回值:以Series或者DataFrame的类型返回数据的排名(哪个类型调用返回哪个类型)
    • rank函数包含有6个参数:
    • axis:设置沿着哪个轴计算排名(0或者1),默认为0按纵轴计算排名
    • numeric_only:是否仅仅计算数字型的columns,默认为False
    • na_option :NaN值是否参与排序及如何排序,固定参数:keep top bottom
    • keep: NaN值保留原有位置
    • top: NaN值全部放在前边
    • bottom: NaN值全部放在最后
    • ascending:设定升序排还是降序排,默认True升序
    • pct:percent是否以排名的百分比显示排名(所有排名与最大排名的百分比),默认False
    • method:排名评分的计算方式,固定值参数,常用固定值如下:
    • average : 默认值,排名评分不连续;数值相同的评分一致,都为平均值
    • min : 排名评分不连续;数值相同的评分一致,都为最小值
    • max : 排名评分不连续;数值相同的评分一致,都为最大值
    • dense : 排名评分是连续的;数值相同的评分一致
    df2
    df2.rank()
    df2.rank(axis=0)
    df2.rank(numeric_only=True) # 只对数值类型的列进行统计
    df2.rank(ascending=False) # 降序
    df2.rank(pct=True) # 以最高分作为1,放回百分数形式的评分,pct参数默认为False
    

    image-20220124010302102

    df2.rank(method='average')
    df2.rank(method='min')
    df2.rank(method='max')
    df2.rank(method='dense')
    

    image-20220124010717941

    rank使用详解

    df7 = pd.DataFrame({
        '姓名':['小明', '小美', '小强', '小兰'],
        '成绩':[100, 90, 90, 80]
    })
    
    df7.rank()  # 等价于df7.rank(method='average', ascending=True)
    
    df7['成绩排名'] = df7.成绩.rank(method='min', ascending=False)
    df7
    
    df7['成绩排名'] = df7.成绩.rank(method='max', ascending=False)
    df7
    
    df7['成绩排名'] = df7.成绩.rank(method='dense', ascending=False)
    df7
    
    最后一种希望大家重点掌握,其他几种搞清楚原理即可。
    
  • 6- 聚合函数:

    常用聚合函数有:

    • min 最小值
    • max 最大值
    • mean 平均值
    • sum 求和
    • count 求个数
    • min函数
    df2.min()
    
    df2['year'].min() 
    
    • max函数
    df2.max()
    df2['year'].max()
    
    • mean 平均值
    df2.mean()
    df2['year'].mean()
    df2['GDP'].mean()
    

七、【掌握】高级处理-缺失值处理

掌握内容

fillna():填充缺失值
dropna(axis=0):删除带有缺失值的行

如何处理NAN

  • 获取缺失值的标记方式(nan或者其他标记方式)

  • 如果缺失值的标记方式是nan

    • 判断数据中是否包含nan:
      • pd.isnull(df),
      • pd.notnull(df)
    • 存在缺失值nan:
      • 1、删除存在缺失值的:dropna(axis)
        • 注:不会修改原数据,需要接受返回值
      • 2、替换缺失值:fillna(value, inplace=True)
        • value:替换成的值
        • inplace:True:会修改原数据,False:不替换修改原数据,生成新的对象
  • 如果缺失值没有使用nan标记,比如使用”?”

    • 先替换‘?’为np.nan,然后继续处理

电影数据的缺失值处理

  • 电影数据文件获取
# 读取电影数据
movie = pd.read_csv("data/movie.csv")

image-20240831130641684

判断缺失值是否存在

  • pd.notnull(DataFrame对象):等同于SQL语句中的 is not null
pd.notnull(movie)

Rank    Title    Genre    Description    Director    Actors    Year    Runtime (Minutes)    Rating    Votes    Revenue (Millions)    Metascore
0    True    True    True    True    True    True    True    True    True    True    True    True
1    True    True    True    True    True    True    True    True    True    True    True    True
2    True    True    True    True    True    True    True    True    True    True    True    True
3    True    True    True    True    True    True    True    True    True    True    True    True
4    True    True    True    True    True    True    True    True    True    True    True    True
5    True    True    True    True    True    True    True    True    True    True    True    True
6    True    True    True    True    True    True    True    True    True    True    True    True
7    True    True    True    True    True    True    True    True    True    True    False    True
  • np.all(pd.notnull(DataFrame对象))
  • pd.isnull(DataFrame对象):等同于SQL语句中的 is null

存在缺失值nan,并且是np.nan

  • 1- 删除

pandas删除缺失值,使用dropna的前提是,缺失值的类型必须是np.nan

# 不修改原数据
movie.dropna()

# 可以定义新的变量接受或者用原来的变量名
data = movie.dropna()
  • 2- 替换缺失值
# 替换存在缺失值的样本的两列
# 替换填充平均值,中位数
 movie['Revenue (Millions)'].fillna(movie['Revenue (Millions)'].mean(), inplace=True)

不是缺失值nan,有默认标记的

数据是这样的:

image-20240831130954530

处理思路分析:

  • 1、先替换‘?’为np.nan

    • df.replace(to_replace=, value=)

      • to_replace:替换前的值
      • value:替换后的值
      # 替换特殊数据,然后对空值进行处理
      df = pd.read_csv("data/breast-cancer-wisconsin.data",encoding="UTF-8")
      # 链式编程
      df4 = df.replace("?",np.nan).dropna()
      df4
      

八、【熟悉】高级处理-数据合并

掌握内容

concat:等价于SQL中的union操作

pd.concat实现数据合并

  • pd.concat([data1, data2], axis=1):等价于SQL中的union操作
    • 按照行或列进行合并
# 拼接concat
"""
    参数解释:
        objs:参与拼接的数据。可以是DF对象,也可以是Series对象,可以两者混合
        axis:0的时候在下面(也就是垂直方向)进行拼接;1的时候在后面(也就是水平方向)进行拼接
"""
con_1 = pd.concat(objs=[df1,df2], axis=0)
con_1 = pd.concat(objs=[df1,df2["A"]], axis=0)
con_1 = pd.concat(objs=[df1,df2], axis=1)
con_1

pd.merge

  • pd.merge(left, right, how=’inner’, on=None):等价于SQL中的join操作
    • 可以指定按照两组数据的共同键值对合并或者左右各自
    • left: DataFrame
    • right: 另一个DataFrame
    • on: 指定的共同键
    • how:按照什么方式连接
Merge methodSQL Join NameDescription
leftLEFT OUTER JOINUse keys from left frame only
rightRIGHT OUTER JOINUse keys from right frame only
outerFULL OUTER JOINUse union of keys from both frames
innerINNER JOINUse intersection of keys from both frames

内连接:

left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
                        'key2': ['K0', 'K1', 'K0', 'K1'],
                        'A': ['A0', 'A1', 'A2', 'A3'],
                        'B': ['B0', 'B1', 'B2', 'B3']})

right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
                        'key2': ['K0', 'K0', 'K0', 'K0'],
                        'C': ['C0', 'C1', 'C2', 'C3'],
                        'D': ['D0', 'D1', 'D2', 'D3']})

# 默认内连接
result = pd.merge(left, right, on=['key1', 'key2'])  # on t1.key1=t2.key1 and t1.key2=t2.key2

image-20240831231631642

左连接

result = pd.merge(left, right, how='left', on=['key1', 'key2'])

image-20240831231730179

右连接

result = pd.merge(left, right, how='right', on=['key1', 'key2'])

image-20240831231751903

外连接

result = pd.merge(left, right, how='outer', on=['key1', 'key2'])

image-20240831231814065

九、【理解】高级处理-数据分组

数据准备

  • 加载优衣库的销售数据集,包含了不同城市优衣库门店的所有产品类别的销售记录,数据字段说明如下
    • store_id 门店随机id
    • city 城市
    • channel 销售渠道 网购自提 门店购买
    • gender_group 客户性别 男女
    • age_group 客户年龄段
    • wkd_ind 购买发生的时间(周末,周间)
    • product 产品类别
    • customer 客户数量
    • revenue 销售金额
    • order 订单数量
    • quant 购买产品的数量
    • unit_cost 成本(制作+运营)
# 导包 加载数据集
import pandas as pd 
df = pd.read_csv('data/uniqlo.csv')

groupby分组聚合

  • 1- df.groupby分组函数返回分组对象

    【基于一列进行分组】

# 基于顾客性别分组
gs = df.groupby(['gender_group'])
gs
gs['city']
# 返回结果如下
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001B1DA988B80>
<pandas.core.groupby.generic.SeriesGroupBy object at 0x000001B1DB2B4FA0>

​ 【基于多列进行分组】

# 基于顾客性别、不同城市分组
gs2 = df.groupby(['gender_group', 'city'])
gs2
# 返回结果如下
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001B1DB24F1F0>
  • 2- 分组后获取各个组内的数据

    • 2.1 取出每组第一条或最后一条数据
    gs2 = df.groupby(['gender_group', 'channel'])
    gs2.first() # 取出每组第一条数据
    gs2.last() # 取出每组最后一条数据
    

    image-20220124012357765

    • 2.2 - 按分组依据获取其中一组
    gs2.get_group(('Female', '线上'))
    

    image-20220124012526559

  • 3- 分组聚合

    • 格式:分组后对多列分别使用不同的聚合函数。agg->aggregate
    df.groupby(['列名1', '列名2']).agg({
        '指定列1':'聚合函数名', 
        '指定列2':'聚合函数名', 
        '指定列3':'聚合函数名'
    })
    
    • 按城市和线上线下划分,分别计算销售金额的平均值、成本的总和
    agg_1 = df.groupby(["city","channel"]).agg(
        {
            "revenue":"mean",
            "unit_cost":"sum"
        }
    )
    agg_1
    

分组聚合过滤操作:==Pandas不支持 groupby().agg().filter==

  • 格式:
df.groupby(['列名1',...]).filter(
   lambda x: dosomething returun True or False
)
案例: 按城市分组,查询每组销售金额平均值大于200的全部数据
df.groupby(['city']).filter(lambda d: d['revenue'].mean() > 200)

df.groupby(['city'])['revenue'].filter(lambda s: s.mean() > 200)

十、【了解】高级处理-交叉表与透视表

交叉表与透视表有什么作用?

探究股票的涨跌与星期几有关?

以下图当中表示,week代表星期几,1,0代表这一天股票的涨跌幅是好还是坏,里面的数据代表比例

可以理解为所有时间为星期一等等的数据当中涨跌幅好坏的比例

image-20260525165533772

image-20260525165613241

  • 交叉表:

    交叉表用于计算一列数据对于另外一列数据的分组个数(用于统计分组频率的特殊透视表)

    • pd.crosstab(value1, value2)
  • 透视表:

    透视表是将原有的DataFrame的列分别作为行索引和列索引,然后对指定的列应用聚集函数

    • data.pivot_table()
    • DataFrame.pivot_table([], index=[])

交叉表

import pandas as pd

# 创建一个示例数据集
data = {
    '性别': ['男', '女', '男', '女', '男', '女', '女', '男'],
    '购买': ['是', '否', '是', '是', '否', '否', '是', '否']
}

df = pd.DataFrame(data)

# 创建交叉表
crosstab = pd.crosstab(df['性别'], df['购买'])
print(crosstab)

购买  否  是
性别        
女    2   2
男    2   2

透视表

import pandas as pd

data = {
    '性别': ['男', '女', '男', '女', '男', '女'],
    '购买': ['是', '否', '是', '是', '否', '否'],
    '金额': [100, 150, 200, 130, 160, 120]
}
df = pd.DataFrame(data)

# 创建透视表
pivot_table = pd.pivot_table(df, values='金额', index='性别', columns='购买', aggfunc='mean')
print(pivot_table)

购买      否     是
性别             
女   135.0  130.0
男   180.0  150.0

案例分析

数据准备

  • 准备两列数据,星期数据以及涨跌幅是好是坏数据
  • 进行交叉表计算
# 寻找星期几跟股票张得的关系
# 1、先把对应的日期找到星期几
date = pd.to_datetime(data.index).weekday
data['week'] = date

# 2、假如把p_change按照大小去分个类0为界限
data['posi_neg'] = np.where(data['p_change'] > 0, 1, 0)

# 通过交叉表找寻两列数据的关系
count = pd.crosstab(data['week'], data['posi_neg'])

但是我们看到count只是每个星期日子的好坏天数,并没有得到比例,该怎么去做?

  • 对于每个星期一等的总天数求和,运用除法运算求出比例
# 算数运算,先求和
sum = count.sum(axis=1)

# 进行相除操作,得出比例
pro = count.div(sum, axis=0)

查看效果

使用plot画出这个比例,使用stacked的柱状图

pro.plot(kind='bar', stacked=True)
plt.show()

使用pivot_table(透视表)实现

使用透视表,刚才的过程更加简单

# 通过透视表,将整个过程变成更简单一些
data.pivot_table(['posi_neg'], index='week')

总结

交叉表和透视表的区别:

  • 交叉表cross_tab:功能简单,适合处理简单任务

  • 透视表pivot_table:功能强大,适合复杂任务

  • 如果你的目标是复杂的数值汇总,请使用 pivot_table;如果你的目标是快速查看分类数据的频数或比例分布,crosstab 会更高效、更直观

------ 本文结束,感谢您的阅读 ------
本文作者: 程序员青阳
版权声明: 本文采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。