数据分析三剑客之Pandas

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

  • Pandas是Python的一个第三方包,也是商业和工程领域最流行的结构化数据工具集,用于数据清洗、处理以及分析

  • Pandas在数据处理上具有独特的优势:

    • 底层是基于Numpy构建的,所以运行速度特别的快

    • 有专门的处理缺失数据的API

    • 强大而灵活的分组、聚合、转换功能

适用场景:

  • 数据量大到Excel严重卡顿,且又都是单机数据的时候,我们使用Pandas

    • Pandas用于处理单机数据(小数据集(相对于大数据来说))
  • 在大数据ETL数据仓库中,对数据进行清洗及处理的环节使用Pandas

1.pandas初体验

python 复制代码
import pandas as pd
import numpy as np
import os
os.chdir(r'D:\LLM\pandasProject')   # 修改相对路径的位置.
# os.getcwd()

# 解决中文显示问题,下面的代码只需运行一次即可
import matplotlib as plt
plt.rcParams['font.sans-serif'] = ['SimHei']    # 如果是Mac本, 不支持SimHei的时候, 可以修改为 'Microsoft YaHei' 或者 'Arial Unicode MS'
plt.rcParams['axes.unicode_minus'] = False

1.1折线图绘制 各国GDP变化趋势

python 复制代码
# 1. 读取数据.
# 绝对路径
# df = pd.read_csv(r'\LLM\pandasProject\data\1960-2019全球GDP数据.csv', encoding='gbk')

# 相对路径
df = pd.read_csv('./data/1960-2019全球GDP数据.csv', encoding='gbk')
df
python 复制代码
# 2. 加载中国的数据.
china_df = df[df.country == '中国']
china_df
python 复制代码
# 3. 设置 year字段为 索引列.
china_df.set_index('year', inplace=True)    # inplace=True, 表示修改原数据.
china_df
python 复制代码
# 4. 绘制折线图 
# china_df.plot()
china_df.GDP.plot()
python 复制代码
# 5. 参考上述思路, 绘制中美日 三国GDP折线图.
usa_df = df[df.country == '美国'].set_index('year')
jp_df = df[df.country == '日本'].set_index('year')
usa_df
jp_df
python 复制代码
# 6. 绘制三国折线图
china_df.GDP.plot()
usa_df.GDP.plot()
jp_df.GDP.plot()

1.2绘制中美日三国 GDP 折线图, 加入图例 -> 拼音

python 复制代码
# 1. 获取中美日三国的数据.
china_df = df[df.country == '中国'].set_index('year')
usa_df = df[df.country == '美国'].set_index('year')
jp_df = df[df.country == '日本'].set_index('year')
china_df
python 复制代码
# 2. 分别修改 中美日三国的 GDP字段名为: 'china', 'usa', 'jp'
china_df.rename(columns={'GDP': 'china'}, inplace=True)
usa_df.rename(columns={'GDP': 'usa'}, inplace=True)
jp_df.rename(columns={'GDP': 'jp'}, inplace=True)
# 3. 查看修改后的数据
china_df
python 复制代码
# 4. 绘制折线图.
china_df.china.plot(legend=True)    # 设置图例
usa_df.usa.plot(legend=True)
jp_df.jp.plot(legend=True)

1.3绘制中美日三国 GDP 折线图, 加入图例 -> 中文

python 复制代码
# 1. 获取中美日三国的数据.
china_df = df[df.country == '中国'].set_index('year')
usa_df = df[df.country == '美国'].set_index('year')
jp_df = df[df.country == '日本'].set_index('year')
china_df
python 复制代码
# 2. 分别修改 中美日三国的 GDP字段名为: '中国', '美国', '日本'
china_df.rename(columns={'GDP': '中国'}, inplace=True)
usa_df.rename(columns={'GDP': '美国'}, inplace=True)
jp_df.rename(columns={'GDP': '日本'}, inplace=True)
# 3. 查看修改后的数据
china_df
python 复制代码
# 4. 绘制折线图.
china_df.中国.plot(legend=True)    # 设置图例
usa_df.美国.plot(legend=True)
jp_df.日本.plot(legend=True)

2.Series对象入门

python 复制代码
# Pandas中有两大核心对象, 分别是: DataFrame和Series, 
# 其中, Series -> 一列数据, DataFrame -> 多列数据

2.1创建Series对象

python 复制代码
# 1. 创建Series对象, 采用: 默认自增索引.
s1 = pd.Series([1,2,3,4,5])
print(s1)
python 复制代码
# 2. 创建Series对象, 采用: 自定义索引.
s2 = pd.Series([1, 2, 3, 4, 5], index=['a', 'b', 'c', 'd', 'e'])
print(s2)
复制代码
python 复制代码
# 3. 使用字典, 元组创建Series对象. 
# 元组形式
s3 = pd.Series((11, 22, 33, 44, 55))
print(s3)

# 字典形式.
s4 = pd.Series({'a': 1, 'b': 3, 'c': 5})
print(s4)
python 复制代码
# 4. 使用numpy -> 创建Series对象.
s5 = pd.Series(np.arange(5))
print(np.arange(5))
print(s5)

2.2Series对象的属性

python 复制代码
# 1. 构建Series对象, 索引为: A-F, 值为: 0-5
# s6 = pd.Series(data=[0, 1, 2, 3, 4, 5], index=['A', 'B', 'C', 'D', 'E', 'F'])

# 加入列表推导式 
s6 = pd.Series(data=[i for i in range(6)], index=[i for i in 'ABCDEF'])
print(s6)

# Series对象的init方法内部参数
# def __init__(
#         self,
#         data=None,
#         index=None,
#         dtype: Dtype | None = None,
#         name=None,
#         copy: bool | None = None,
#         fastpath: bool | lib.NoDefault = lib.no_default,
#     ) -> None:
python 复制代码
# 2. 获取Series对象的 索引列(的值)
print(s6.index)     # Index(['A', 'B', 'C', 'D', 'E', 'F'], dtype='object')

# 3. 获取Series对象的 值列(的值)
print(s6.values)    #[0 1 2 3 4 5]

# 4. Series支持根据 索引 获取元素, 即: Series对象[索引值]
print(s6['D'])  # 3

# 5. 根据索引, 修改Series对象的 元素值
s6['D'] = 99
print(s6)

3.DataFrame对象入门

3.1创建DataFrame对象

python 复制代码
# 场景1: 通过 字典 + 列表的方式实现. 
# 1. 准备数据集, 每个键值对 = 1列数据
info = {
    'name': ['路人甲', '路人乙', '路人丙', '路人丁'],
    'gender': ['女', '男', '保密', '保密'],
    'age': [81, 80, 66, 55]
}

# 2. 把上述的数据集, 封装成DataFrame对象.
df1 = pd.DataFrame(data=info)

# 3. 打印结果.
df1
python 复制代码
# 场景2: 通过 列表 + 元组(或者列表) 的方式实现.
# 1. 准备数据集, 每个元组 = 1行数据
info = [
    ('刘亦菲', '女', 39),
    ('迪丽热巴', '女', 31),
    ('王四', '未知', 66),
]

# info = [
#     ['刘亦菲', '女', 39],
#     ['迪丽热巴', '女', 31],
#     ['王四', '未知', 66],
# ]

# 2. 把上述的数据集, 封装成DataFrame对象.
df2 = pd.DataFrame(data=info, columns=['姓名', '性别', '年龄'])
df2
python 复制代码
# 场景3: 通过 numpy的ndarray -> pandas DataFrame 的方式实现.
# 1. 创建numpy的 ndarray对象.
arr1 = np.arange(12).reshape(3, 4)
arr1
python 复制代码
# 2. 把上述的ndarray对象, 封装成DataFrame对象.
df3 = pd.DataFrame(data=arr1, columns=['a', 'b', 'c', 'd'])
df3

3.2DataFrame小案例

python 复制代码
# 1. 生成10名同学, 5门功课的成绩, 成绩范围: 40 ~ 100
score_df = pd.DataFrame(np.random.randint(40, 101, (10, 5)))    # 10行, 5列   包左不包右
score_df
python 复制代码
# 2. 修改DataFrame对象的 列名 和 索引列值.
column_names = ['语文', '数学', '英语', '政治', '体育']

# print(score_df.shape)  # (10, 5)
# index_names = ['同学0', '同学1', '同学2', '同学3', '同学4', '同学5', '同学6', '同学7', '同学8', '同学9']
index_names = ['同学' + str(i) for i in range(score_df.shape[0])]

# 3. 具体的修改DataFrame对象 列名 和 索引值的动作.
# score_df.columns = column_names
# score_df.index = index_names

# rename函数也可以.
# score_df.rename(index={0:'同学0', 1:'同学1'}, columns={0: '数学', 1: '语文'}, inplace=True)

#                 i的值: 0 ~ 9                        i的值: 0 ~ 4 
score_df.rename(
    index={i:index_names[i] for i in range(score_df.shape[0])}, 
    columns={i: column_names[i] for i in range(score_df.shape[1])}, 
    inplace=True
)

# 4. 打印修改后的结果.
score_df

3.3DataFrame的基本属性

python 复制代码
# shape 维度, 即: 行列数
print(score_df.shape)   # (10, 5)

# index: 索引列
print(score_df.index)
# Index(['同学0', '同学1', '同学2', '同学3', '同学4', '同学5', '同学6', '同学7', '同学8', '同学9'], dtype='object')

# columns: 列名
print(score_df.columns)
# Index(['语文', '数学', '英语', '政治', '体育'], dtype='object')

# values: 数据(值)
print(score_df.values)
# [[86 68 88 69 70]
#  [73 97 88 61 65]
#  [62 69 67 84 73]
#  [60 46 52 79 90]
#  [52 48 73 77 99]
#  [71 82 43 55 52]
#  [64 66 63 85 53]
#  [99 96 81 81 75]
#  [69 57 80 87 63]
#  [88 67 41 58 54]]
python 复制代码
# 行列转置, T
score_df.T

3.4DataFrame的基本函数

python 复制代码
# 1. 查看df对象
score_df

# 2. head(n), 查看前n行数据
# score_df.head()     # 默认是 5 条
score_df.head(3)      # 指定数据条数

# 3. tail(n), 查看后n行数据
# score_df.tail()     # 默认是 5 条
score_df.tail(2)    # 指定数据条数
python 复制代码
# 4. info(), 查看df对象的详细信息
score_df.info()
python 复制代码
# 5. describe(), 查看df对象的 描述性 统计信息
score_df.describe()
python 复制代码
# 6. reset_index() 重置索引列.
# score_df.reset_index(drop=False)    # drop=False, 默认值, 不删除原索引列.

score_df.reset_index(drop=True)       # drop=True, 删除原索引列.
python 复制代码
# 7. set_index(): 重新设置索引.
# score_df.set_index('语文')        # 语文成绩充当索引列.

# 语文, 英语充当索引列. 
score_df.set_index(['语文', '英语'])

3.5Pandas的数据类型介绍

python 复制代码
# Pandas中的数据类型几乎和Python中是一致的, 只不过有几个不太一样.
# 例如: Python: str -> Pandas: object,  Python: None -> Pandas: nan,NAN,NaN,    
# Pandas还支持category分类类型, 针对于分类数据操作更快, 更节省内存. 

# 1. 创建DataFrame对象.
df = pd.DataFrame({
    'name': [np.NaN, '路人甲', '路人乙', '路人cc'],
    'gender': ['女', '男', '保密', np.nan],
    'age': [81, 80, np.NAN, 55]
})

df
python 复制代码
# 2. 查看df对象的 详细信息
df.info()
python 复制代码
# 3. 演示 日期类型 datetime
df2 = pd.DataFrame(['2025-03-29', '2025-03-30', '2025-03-31'], columns=['date'],dtype='datetime64[ns]')
print(df2)
print(df2.dtypes)
python 复制代码
# 4. 演示 日期差类型 timedelta
start_date = pd.to_datetime('2004-08-21')
end_date = pd.to_datetime('2025-03-29')

# 打印结果
print(end_date - start_date)
print(type(end_date - start_date))

# 7525 days 00:00:00
# <class 'pandas._libs.tslibs.timedeltas.Timedelta'>
python 复制代码
# 5. 演示下 category类型
s1 = pd.Series(['男', '女', '保密'], dtype='category')
print(s1)
print(type(s1))
print(s1.dtypes)    # category

4.Pandas的基本操作

4.1加载数据

python 复制代码
# 1. 加载数据
df = pd.read_csv('./data/stock_day.csv')
df
python 复制代码
# 2. 移除不需要的字段. 
df.drop(columns=['ma5', 'ma10', 'ma20', 'v_ma5', 'v_ma10', 'v_ma20'], axis=0, inplace=True)   # 0: 列, 1: 行

# 注意:删除过后,重复删除会因找不到对应的 列索引列 而报错哈 
python 复制代码
# 3. 查看处理后的数据.
df              # 查看数据.
# df.info()       # 查看详细信息
# df.describe()   # 查看描述性统计信息

4.2索引操作

python 复制代码
# 场景1: 根据行列索引获取元素, 先列后行.
df['open']['2018-02-23']    # 22.88

# 尝试用: 先行后列
# df['2018-02-23']['open']    # 错误写法
python 复制代码
# 场景2: 结合 loc 根据: 行索引值 和 列索引值 来获取元素.
# 格式: df.loc[行索引值, 列索引值]
# 格式: df.iloc[行索引号, 列索引号]
df.loc['2018-02-27', 'high']        # 获取一条数据
df.loc['2018-02-27':'2018-02-14', ['open', 'high']] #多条数据
python 复制代码
# 场景3: 结合 iloc 根据: 行索引号 和 列索引号 来获取元素.
df.iloc[0:5, 0:2]   # 获取多条数据

4.3赋值操作

python 复制代码
# 1. 查看源数据.
df

# 2. 赋值操作
df['open'] = 23
df.low = 1         
# 效果同上, 更简单, 但是有弊端, 如果 字段有空格等, 该方式不行. 
#例如:  df.max value 必须写成 df['max value']

# 3. 查看结果
df

4.4排序操作

python 复制代码
# 1. 查看原数据
df

# 2. 基于开盘价格做 升序 排列.
# df.sort_values(by='open', ascending=True)   # 升序.
df.sort_values(by='open', ascending=False)    # 降序.

# 3. 基于开盘价格降序排列, 价格一样, 基于 当日最高价格(high) 降序排列.
df.sort_values(by=['open', 'high'], ascending=[False, False])

# 4. 按照索引排序.
df.sort_index(ascending=True)   # 默认升序.

# 5. 演示 Series对象也有 sort_index(), sort_values() 排序方法.
# df.open.sort_index(ascending=True)    # 索引升序
df.open.sort_values(ascending=False)    # 价格降序

5.DataFrame运算

5.1算数运算

python 复制代码
# 1. 查看源数据.
df

# 2. 针对于 close列值 + 2 处理.
# df.close.add(2)       # 效果同下
df.close + 2        # Series对象 和 数值运算, 则 Series中的每个数值都会和该数字进行运算.

# 3. 针对于 low列的值 - 10 处理
# df.low.sub(10)
df.low - 10     # 效果同上

5.2逻辑运算符 & |

python 复制代码
# 1. 查看源数据.
df

# 2. 完成需求.
# 需求1: 筛选出 open列值 > 23的数据. 
df[df.open > 23]

# 需求2: 筛选出 open列值 > 23, 且 < 24的数据.
df[(df.open > 23) & (df.open < 24)]           # 细节: 多组判断记得加 小括号.

df[(df['open'] > 23) & (df['open'] < 24)]     # 标准写法.

# 3. 可以通过 query()函数, 优化上述的代码.
df.query('open > 23 & open < 24')

# 4. 固定值的筛选, isin
# 需求: 查询 open价格为 23.53, 23.67价格数据.
df[(df.open == 23.53) | (df.open == 23.67)]
df[df.open.isin([23.53, 23.67])]

df.query('open == 23.53 | open == 23.67')
df.query('open in [23.67, 23.53]')

5.3统计函数

python 复制代码
# 1. 查看源数据
df

# 2. 演示常用的统计函数
df.describe()   # 查看各列的描述性的 统计信息, 例如: 个数, 最大值, 最小值, 平均值, 中位数, 25%分位数, 75%分位数.
python 复制代码
# 统计函数 count(), mean(), median(), min(), max(), std(), var(), sum()

df.sum()        # 针对于 每列(DataFrame对象) 进行求和.
df.high.sum()   # 针对于 high列(Series对象) 进行求和.
df.mean()       # 针对于 每列(DataFrame对象) 进行求平均值.
df.median()     # 针对于 每列(DataFrame对象) 进行求中位数.

df.cumsum()     # 针对于 每列(DataFrame对象) 进行求累计求和.
python 复制代码
# - apply()函数 -> 它可以执行自定义函数

# 背景: 目前我们用的都是Pandas提供好的函数, 例如: count(), max(), min()...
# 如果要传入一些自定义的逻辑, 此时就需要用到 apply()函数了
# 格式: df.apply(自定义函数, axis=0)   # 0 -> 列, 1 -> 行


# 需求: 同时 获取到 多列的 最大值 和 最小值的差值.  例如: open列, close列
# df.open.max() - df.open.min()
# df.close.max() - df.close.min()

# 思路1: 分解版.
# 1. 自定义函数 my_func, 接收 某列的数据, 计算该列的最大值和最小值, 返回差值.
def my_func(col):
    return col.max() - col.min()

# 2. 获取到 open列和 close列.
df[['open', 'close']]
df.loc[:, ['open', 'close']]
df.iloc[:, [0, 2]]
df.iloc[:, 0:3:2]

# 3. 通过apply()函数, 调用上述的自定义函数, 作用到 指定的列.
df[['open', 'close']].apply(my_func, axis=1)  # axis=1, 表示对 行 进行操作.
df[['open', 'close']].apply(my_func, axis=0)  # axis=0, 表示对 列 进行操作.
# df[['open', 'close']].apply(my_func)  # 效果同上, 默认是axis=0,  底层 -> 把df的各列分别传入函数, 计算结果.

# 思路2: 合并版, 通过 lambda函数实现.
df[['open', 'close']].apply(lambda col: col.max() - col.min())

6.Pandas读写操作

python 复制代码
import pandas as pd
import numpy as np
import os
os.chdir(r'D:\LLM\pandasProject')   # 修改相对路径的位置.
# os.getcwd()

# 解决中文显示问题,下面的代码只需运行一次即可
import matplotlib as plt
plt.rcParams['font.sans-serif'] = ['SimHei']    # 如果是Mac本, 不支持SimHei的时候, 可以修改为 'Microsoft YaHei' 或者 'Arial Unicode MS'
plt.rcParams['axes.unicode_minus'] = False

from sqlalchemy import create_engine    # 导入sql引擎对象

6.1Pandas操作csv文件

python 复制代码
# 1. 读取csv文件, 获取数据.
# 参数解释: 参1: 文件路径, 参2: 分隔符, 参3: 读取的列名.
df = pd.read_csv('./data/stock_day.csv', sep=',', usecols=['open', 'high', 'close', 'low'])
df

# 2. 把读取到的数据, 写到文件中.
df[:10].to_csv('./data/my_file1.csv', sep=',', index=False)  # 参数3: 是否写入索引.
print('写入成功!')

# 3. 特殊的csv文件 -> tsv文件. 
# 区别: csv文件 -> 以,做分割,    tsv文件 -> 是以tab键分隔的.
df[:5].to_csv('./data/my_file2.tsv', sep='\t', index=True)
print('写入成功!')

# 4. 读取tsv文件.
# 参1: 文件路径, 参2: 分隔符, 参3: 把索引为0的列(第1列) 设置为索引.
df2 = pd.read_csv('./data/my_file2.tsv', sep='\t', index_col=0)
df2

6.2Pandas操作MySql数据表

python 复制代码
# 前提: 你的Anaconda要先装: pymysql 和 sqlalchemy 模块.
# 安装方式: pip install 模块名
# pip install pymysql==1.0.2 -i https://pypi.tuna.tsinghua.edu.cn/simple/
# 如果后边的代码运行提示找不到sqlalchemy的包,和pymysql一样进行安装即可
# pip install sqlalchemy==2.0.0 -i https://pypi.tuna.tsinghua.edu.cn/simple/


# 此外, 你的电脑还需要安装并运行: mysql数据库

# 需求: 把数据写入到MySQL数据表.
# 1. 准备写到MySQL数据表的 数据.
data = pd.read_csv('./data/csv示例文件.csv', encoding='gbk', index_col=0)
data

# 2. 导包
# from sqlalchemy import create_engine    # 导入引擎对象, 我们写到第1个单元格了.

# 3. 创建引擎对象.
#                       数据库+模块名://数据库的用户名:密码@主机名:端口号/要操作的数据库名?编码方式'
engine = create_engine('mysql+pymysql://root:root@localhost:3306/tb?charset=utf8')

# 4. 具体的往数据库写数据的动作.
# 参1: 数据表名, 参2: 引擎对象, 参3: 是否把索引写入数据库, 
# 参4: 如果数据表存在, 则如何处理(append->追加数据; replace->覆盖数据)
data.to_sql('my_table', engine, index=False, if_exists='append')

# 5. 提示
print('写入成功!')

# 6. 从SQL表中读取数据.
# 参1: 数据表名, 参2: 引擎对象.
sql_df = pd.read_sql('my_table', engine)    # 读取全表.
sql_df = pd.read_sql('select name, AKA from my_table limit 0,2', engine)    # 读取表中指定数据..
sql_df

原生的pymysql

python 复制代码
# 这个代码是原生pymysql, 掌握 pandas 读写mysql的方式已经够用了.

# 导包
import pymysql

# 1. 获取连接对象(Python -> MySQL)        前台小姐姐
conn = pymysql.connect(
    host='127.0.0.1', # 数据库地址
    port=3306, # 数据库端口
    user='root', # 数据库用户名
    password='root', # 数据库密码
    database='tb', # 数据库名称
    charset='utf8' # 数据库编码
)

# 2. 根据连接对象, 获取游标对象             我 ->找人的
cursor = conn.cursor()

# 3. 定义SQL语句
sql = 'select name, AKA from my_table limit 0,2'

# 4. 并执行SQL语句
cursor.execute(sql)

# 5. 获取结果集
result = cursor.fetchall()

# 6. 遍历结果集.
for row in result:
    print(row)

# 7. 释放资源.
cursor.close()
conn.close()

6.3Pandas读写josn文件

python 复制代码
# 1. 读取json文件.
# 参1: 文件路径, 参2: 读取的格式, 参3: 是否按行读取.

json_df = pd.read_json('./data/test.json', orient='records', lines=True)
# 2. 打印读取到的内容.
json_df
python 复制代码
# 2. 把上述的数据, 写到json文件中.
# json_df.to_json('./data/my_file3.json', orient='records')   # 结果为: [{}, {}, {}...]
# json_df.to_json('./data/my_file3.json', orient='records', lines=True)   # 结果为: {} {} {}... 逐行形式

# json_df.to_json('./data/my_file3.json')     # 格式为: columns: {...}
# json_df.to_json('./data/my_file3.json', orient='index')     # 格式为: index: {...}


json_df.to_json('./data/my_file3.json', orient='records', lines=True)   # 结果为: {} {} {}... 逐行形式
print('写入成功!')



        # - ``'split'`` : dict like
        #   ``{{index -> [index], columns -> [columns], data -> [values]}}``
        # - ``'records'`` : list like
        #   ``[{{column -> value}}, ... , {{column -> value}}]``
        # - ``'index'`` : dict like ``{{index -> {{column -> value}}}}``
        # - ``'columns'`` : dict like ``{{column -> {{index -> value}}}}``
        # - ``'values'`` : just the values array
        # - ``'table'`` : dict like ``{{'schema': {{schema}}, 'data': {{data}}}}```

7.Pandas的CURD操作

7.1Pandas的CURD操作-增

python 复制代码
# 1. 准备数据.
df = pd.read_csv('./data/1960-2019全球GDP数据.csv', encoding='gbk')

# 2. 从原始数据集中 拷贝一部分出来 做操作. 
df2 = df[:5].copy()

# 3. 新增列. 

# 思路1: 通过直接 赋值 的方式 新增1列.    column, 列
df2['c1'] = 23              # 写法1: 固定值 
df2['c2'] = ['cxk', 'lyf', 'wyf', 'wyb', '水冷哥'] # 写法2: 传入列表
df2['c3'] = df2.year * 2    # 写法3: 通过已有的列(Series) 来计算新列的值.
def my_fun1():
    return 25000
df2['c4'] = my_fun1()       # 写法4: 通过函数来计算新列的值.


# 思路2: 通过 assign() 的方式 新增1列.

# 写法1: 通过 assign()函数 -> 新增1列.
df3.assign(c1 = 23)

# 写法2: 通过 assign()函数 -> 新增n列.
df3.assign(
    c1 = 23,
    c2 = ['cxk', 'lyf', 'wyf', 'wyb', '水冷哥'],
    c3 = df3.year * 2,
    c4 = my_fun1()
)

7.2Pandas的CURD操作-删和去重

python 复制代码
# 1. 准备数据.
df4 = df[:10].copy()

# 2. 删除行 -> drop()函数, 除非指定inplace=True, 否则不会修改原始数据.
# df4.drop(index=[0, 2, 4])         # 不会修改原始数据.
df4.drop(index=[0], inplace=True)   # 会修改原始数据.

# 3. 删除列 -> del关键字, 会直接修改原数据.
del df4['year']     # 删除year列.

# 4. 删除列 -> drop()函数
# df4.drop(columns=['country'], inplace=True)

# 5. 去重. 
# 场景1: DataFrame去重 -> 以 行 做单位比较.
# 拼接df5 和 df5 -> 组合成 有重复数据的 DataFrame.
df6 = pd.concat([df5, df5])
# DataFrame去重
df6.drop_duplicates()   # 如果设置inplace=True, 则会修改原始数据.

# 场景2: Series去重 -> 以 列 做单位比较.
df6.country.drop_duplicates()

7.3Pandas的CURD操作-改

python 复制代码
# 1. 准备源数据.
df7 = df[:5].copy()

# 2. 新增1列
df7['c1'] = 23

# 3. 修改GDP列值.
df7['GDP'] = [1, 2, 1, 66666666, -123]  # 直接修改原数据了.

# 4. 采用 replace()替换.
# 美国 -> usa
df7.country.replace('美国','usa', inplace=True)
# 日本 -> 岛国
df7.country.replace('日本','jp', inplace=True)

7.4Pandas的CURD操作-查和排序

python 复制代码
# 1. 查看源数据
df

# 2. 获取前5条数据.
df.head(5)
df.head()   # 效果同上, 默认是5条

# 3. 获取后3条数据.
df.tail(3)

# 4. 根据列名获取数据.
df['year']          # 获取year列 -> Series对象
df.year             # 获取year列 -> Series对象, 效果同上.

df[['year']]        # 获取year列 -> DataFrame对象

df[['year', 'country']]     # 获取year和country列 -> DataFrame对象

# 5. 根据 行索引值来获取数据.
df[:5]      # 前5条
df[1:5:2]   # 1, 3, 包左不包右.
df[10::5]   # 从10开始, 到末尾结束, 步长为 5

# 6. 通过query()函数, 结合条件获取.
# 需求: 查询中美日三国 2015 ~ 2019年的数据.
df.query('country in ["中国", "美国", "日本"] and year in [2015, 2016, 2017, 2018, 2019]')
df.query('country in ["中国", "美国", "日本"] and (year >= 2015 and year <= 2019)')

# 7. 排序.
df.sort_index(ascending=False)      # 根据 行索引值排序, 降序.


# 根据内容, 例如: year 降序, 一致就根据 GDP降序.
df.sort_values(['year', 'GDP'], ascending=False)
df.sort_values(['year', 'GDP'], ascending=[False, True])    # year 降序, GDP升序.

# 8. rank()函数, 类似于SQL的窗口函数. 
df7 = pd.DataFrame({
    '姓名':['小a', '小b', '小c', '小d'],
    '成绩':[100, 90, 90, 80]
})

# 9. rank()直接排名
# df7.rank()      # 针对于每列都会排名

# 给df新增1列, 用于显示排名.
df7['成绩排名_min'] = df7.成绩.rank(method='min', ascending=False) # 最小值排名
df7['成绩排名_max'] = df7.成绩.rank(method='max', ascending=False) # 最大值排名
df7['成绩排名_dense'] = df7.成绩.rank(method='dense', ascending=False) # 稠密排名
df7['成绩排名_avg'] = df7.成绩.rank(method='average', ascending=False) # 平均值排名
df7['成绩排名_默认'] = df7.成绩.rank(ascending=False) # 默认

df7

8.Pandas进阶语法

python 复制代码
import pandas as pd
import numpy as np
import os
os.chdir(r'D:\LLM\pandasProject')   # 修改相对路径的位置.
# os.getcwd()

# 解决中文显示问题,下面的代码只需运行一次即可
import matplotlib as plt
plt.rcParams['font.sans-serif'] = ['SimHei']    # 如果是Mac本, 不支持SimHei的时候, 可以修改为 'Microsoft YaHei' 或者 'Arial Unicode MS'
plt.rcParams['axes.unicode_minus'] = False

8.1缺失值处理

思路1:删除缺失值

python 复制代码
#思路1: 删除缺失值

# 1. 读取数据.
movie_df = pd.read_csv('./data/movie.csv')

# 2. 查看下数据的介绍.
movie_df.columns        # 所有的列名
movie_df.info()         # 查看数据的 基本信息(列名, 数据类型, 非缺失值数量等)
movie_df.describe()     # 查看数据的 描述性统计信息(均值, 中位数, 标准差等)

# 3. 删除缺失值
# movie_df.dropna()   # 不会修改原数据, 加入 inplace=True 即可, 默认删: axis=0, 删行, axis=1, 删列.

movie_df.dropna(axis=0)     # 删行,默认删除行
movie_df.dropna(axis=1)      # 删列

思路2:填充缺失值

python 复制代码
# 思路2:填充缺失值

# 1. 查看源数据
movie_df

# 2. 判断某列(的某个值)是否有缺失值. 
pd.isnull(movie_df)     # 判断df对象的 每列的 每个值 是否为空(缺失值)
pd.notnull(movie_df)    # 判断df对象的 每列的 每个值 是否不为空(非缺失值)

# 3.判断某列是否是 包含缺失值的列. 
np.all(pd.notnull(movie_df.Title))    # 整列都是True -> 结果是True, 但凡有False -> 结果是False, 说明该列有缺失.
np.all(pd.notnull(movie_df))    # 整表都是True -> 结果是True, 但凡有False -> 结果是False, 说明该表有缺失.

# 4. 填充缺失值.
# 写法1: 填充固定值.
movie_df.fillna(23)

# 写法2: 填充 每列的平均值.
movie_df['Revenue (Millions)'].fillna(movie_df['Revenue (Millions)'].mean(), inplace=True)
movie_df['Metascore'].fillna(movie_df['Metascore'].mean(), inplace=True)

# 5. for循环的方式, 使用 每列的平均值 来填充各列的缺失值. 
# 5.1 获取每个列名
for col_name in movie_df.columns:
    # 5.2 判断某列是否有缺失值.
    # movie_df[col_name]:  根据列名, 找到 df中的某个列 -> Series对象.
    # pd.notnull(某列数据): 判断该列的每个值是否为非缺失值, True -> 不为空, False -> 为空(缺失值)
    # np.all([True, False...]): 里边的值全部为True -> 结果为True, 只要有一个为False -> 结果为False.
    if np.all(pd.notnull(movie_df[col_name])) == False:
        # 5.3 走到这里, 说明该列有缺失值.
        print(col_name)     # 打印列名
        # 5.4 打印这两列的平均值. 
        print(movie_df[col_name].mean())
        # 5.5 用该列的平均值来填充该列的缺失值.
        movie_df[col_name].fillna(movie_df[col_name].mean(), inplace=True)

思路3:转换,然后填充或者删除缺失值

python 复制代码
# 背景: 实际开发中, 不是所有的缺失值都会用NaN来表示, 例如: 可能用 ? 表示, 如何删除这些缺失值呢? 
# 思路: 先转换, 后删除.  即:  ? -> NaN -> 删除.

# 1. 加载数据.
wis = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data")
wis

# 2. 尝试直接删除缺失值.
wis.dropna()        # ? 不是缺失值, 所以直接删, 删不掉. 

# 3. 解决上述的问题, ? -> NaN -> 删.            空的三种写法: np.nan, np.NAN, np.NaN
wis.replace('?', np.nan).dropna()

8.2数据合并

思路1:concat(),能行合并,能列合并

python 复制代码
# 1. 准备数据. 
df = pd.read_csv('./data/1960-2019全球GDP数据.csv', encoding='gbk')

df1 = df[:10]

df2 = df[10:20]

# 2. 通过 concat() 合并数据.
# 细节: 列合并默认参考 列名.  
new_df = pd.concat([df1, df2], axis=0)  # axis=0, 列合并(垂直合并), axis=1, 行合并(水平合并)
new_df = pd.concat([df1, df2])          # 效果同上, 默认是 垂直列合并

# 细节: 行合并, 默认参考 行索引(值)
new_df = pd.concat([df1, df2], axis=1)  # 水平行合并
new_df

# 3. 行合并. 
# join默认是outer: 满外连接, 即: 左表全集 + 右表全集 + 交集
pd.concat([df1, df2], axis=1, join='outer')    

# 指定为: 内连接, 即: 只要交集
pd.concat([df1, df2], axis=1, join='inner') 

思路2:merge() -> 只能进行 行合并(水平合并)

pd.merge(left, right, how='inner', on=None)

  • 可以指定按照两组数据的共同键值对合并或者左右各自

  • left: DataFrame

  • right: 另一个DataFrame

  • on: 指定的共同键

  • how:按照什么方式连接

python 复制代码
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']})

# 默认内连接(两表交集)
pd.merge(left, right)      # 效果同上, 默认是 inner join, 且参考 同名列进行合并.
result = pd.merge(left, right, how='inner' ,on=['key1', 'key2']) #与上面等同
python 复制代码
# 左外连接(左表全集 + 交集)
result = pd.merge(left, right, how='left', on=['key1', 'key2'])
python 复制代码
# 右外连接(右表全集 + 交集)
result = pd.merge(left, right, how='right', on=['key1', 'key2'])
python 复制代码
# 外连接(满连接)
result = pd.merge(left, right, how='outer', on=['key1', 'key2'])

8.3分组聚合

python 复制代码
# agg -> Aggregate(聚合的意思)
# 格式: df.groupby(['分组字段1', '分组字段2'...]).agg({'列名1':'聚合函数名', '列名2':'聚合函数名'...})

# 1. 场景1: 按照单列分组
df.groupby(['city'])        # DataFrameGroupBy  -> DataFrame分组对象
df.groupby('city')        # 细节: 如果分组列只有1个, 中括号可以省略不写.

# 2. 场景2: 按照多列分组
df.groupby(['city', 'channel'])             # DataFrameGroupBy  -> DataFrame分组对象
df.groupby(['city', 'channel']).revenue     # SeriesGroupBy  -> Series分组对象

# 3. 场景3: 如何获取某个分组的数据. 
df.groupby(['city', 'channel']).get_group(('北京', '线下'))     # 1个分组的信息
df.groupby(['city', 'channel']).get_group(('上海', '线上'))     # 另1个分组的信息
python 复制代码
# 4. 场景4: 分组 + 聚合(聚合字段只有1个)
# 需求: 根据 城市 和 销售渠道分组, 计算: 销售金额.

# 写法1: 通用版(掌握)
df.groupby(['city', 'channel']).agg({'revenue':'sum'})      # 返回DataFrame对象

# 写法2: 变形版(了解)
df.groupby(['city', 'channel']).revenue.sum()               # 返回Series对象
df.groupby(['city', 'channel'])['revenue'].sum()            # 返回Series对象
df.groupby(['city', 'channel'])[['revenue']].sum()          # 返回DataFrame对象
python 复制代码
# 5. 场景5: 分组 + 聚合(聚合字段有2个, 聚合操作相同)
# 需求: 根据 城市 和 销售渠道分组, 计算: 销售金额, 订单数量 总和.

# 写法1: 通用版(掌握)
df.groupby(['city', 'channel']).agg({'revenue':'sum', 'order':'sum'})

# 写法2: 变形版(了解)
df.groupby(['city', 'channel'])[['revenue', 'order']].sum()
python 复制代码
# 6. 场景6: 分组 + 聚合(聚合字段有2个, 聚合操作不同)
# 需求: 根据 城市 和 销售渠道分组, 分别计算: 销售金额的平均值, 成本的总和.
df.groupby(['city', 'channel']).agg({
    'revenue': 'mean',
    'unit_cost': 'sum'
})

8.4分组过滤

python 复制代码
# 需求: 按照城市分组, 查询每组销售金额平均值 大于200的全部数据.    即: 算出每组的销售金额, 找到金额大于200的组, 然后显示这些组所有的信息.

# 1.根据城市分组, 计算每个城市的 销售金额的 平均值
df.groupby('city').revenue.mean()       

# 2. 根据城市分组, 查看上海分组的数据.
df.groupby('city').get_group('上海')
df.query('city in ["上海"]')  # 效果同上

# # 3. 完成需求.
df.groupby('city').filter(lambda x: x.revenue.mean() > 200)
df.groupby('city').revenue.filter(lambda x: x.mean() > 200)

8.5交叉表(了解)、透视表(掌握)

python 复制代码
# 1. 交叉表演示: 
# 创建一个示例数据集
data = {
    '性别': ['男', '女', '男', '女', '男', '女', '女', '男'],
    '购买': ['是', '否', '是', '是', '否', '否', '是', '否']
}

df = pd.DataFrame(data)

# 创建交叉表
crosstab = pd.crosstab(df['性别'], df['购买'])
print(crosstab)
python 复制代码
# 2. 用透视表完成上述的需求.
data = {
    '性别': ['男', '女', '男', '女', '男', '女'],
    '购买': ['是', '否', '是', '是', '否', '否'],
    '金额': [100, 150, 200, 130, 160, 120]
}
df = pd.DataFrame(data)
df.pivot_table(index='性别', columns='购买', values='金额' , aggfunc='mean')
python 复制代码
# 3. 透视表案例: 优衣库数据集.
# 3.1 读取数据
df = pd.read_csv('./data/uniqlo.csv')
df

# 3.2 需求: 根据城市, 销售渠道分组, 计算 销售金额 总和.
# 写法1: groupby() 分组 聚合 
df.groupby(['city', 'channel']).agg({'revenue': 'sum'})
python 复制代码
df.groupby(['city', 'channel'], as_index=False).agg({'revenue': 'sum'})     # as_index=False 不把分组字段当做行索引, 而是当做列.
python 复制代码
# 写法2: pivot_table() 透视表, 作用: 统计分组数据, 简化 分组聚合写法, 指定某一列对另一列的关系
# 参1: 指定分组字段, 参2: 指定分组字段, 参3: 指定聚合字段, 参4: 指定聚合函数
df.pivot_table(index='city', columns='channel', values='revenue', aggfunc='sum')
相关推荐
callJJ1 小时前
Spring AI 语音合成(TTS)完全指南:OpenAI Text-to-Speech
java·人工智能·spring·语音识别·spring ai
诸葛务农1 小时前
AI计算平台前沿进展:下一代AI计算平台——“OpenEmbodied AI Platform (OEAP)设计框架(2)
人工智能
诸葛务农1 小时前
AI计算平台前沿进展:下一代AI计算平台——“OpenEmbodied AI Platform (OEAP)设计框架(1)
人工智能
Baihai IDP1 小时前
Prompt caching 技术是如何实现 1 折的推理成本优化的?
人工智能·ai·llm
燃燃说AI2 小时前
找了3天终于找到!Seedance2.0在哪可以用(附保姆级教程)
人工智能
lisw052 小时前
Spec-Driven Development,规格驱动开发:程序开发新模式!
人工智能·驱动开发·机器学习
power 雀儿2 小时前
VS2026+LibTorch(CPU版)环境搭建
人工智能
德育处主任2 小时前
『n8n』让大模型识别图片内容
人工智能·llm·aigc