Pandas基础入门学习笔记:从核心概念到实操代码
前言
本文是Pandas基础知识的实操性学习笔记,涵盖核心数据结构、Series与DataFrame的关键用法,所有代码可直接复制运行,适合零基础入门者快速上手~
一、Pandas核心认知:数据结构与Python原生结构对比
Pandas的核心是带标签的数据容器,解决Python原生结构(列表、字典)在数据分析中的不足,先明确核心数据结构与原生结构的异同。
1.1 核心数据结构概览
Pandas有3种数据结构,重点掌握前2种:
| 数据结构 | 维度 | 描述 | 类比对象 |
|---|---|---|---|
| Series | 一维 | 带索引的数组(值+索引+名称) | 强化版列表(带标签) |
| DataFrame | 二维 | 带行/列索引的表格(多个Series组成) | Excel表格/数据库表 |
| Panel | 三维 | 存储多个DataFrame(极少用) | 多个Excel工作表 |
1.2 与Python原生结构的异同
| 对比维度 | Pandas(Series/DataFrame) | Python原生结构(列表/字典) |
|---|---|---|
| 索引特性 | 支持自定义标签(字符串、日期等) | 列表仅整数索引,字典键无表格关联 |
| 数据类型 | 列内类型统一(Series),列间可不同(DataFrame) | 列表可混合多类型,字典值无约束 |
| 功能支持 | 内置筛选、统计、时间运算等分析功能 | 仅基础增删改查,无数据分析能力 |
| 性能 | 基于NumPy,大数据量运算快 | 数据量大时运算慢,需手动优化 |
| 相同点 | 均支持迭代、切片,可相互转换(如列表→Series) | 均支持迭代、切片,可相互转换(如列表→Series) |
二、Series:一维带标签数组的实操
Series是Pandas的基础组件,本质是"值+索引+名称"的组合,先明确定义,再掌握创建与属性操作。
2.1 什么是Series?
- 定义:由
values(数据值)、index(索引标签)、name(名称)组成的一维序列,可理解为"带列名的单列数据"。 - 核心作用:存储单列数据(如某商品月度销量)、作为DataFrame的列/行。
2.2 Series创建:5种高频方式(附代码)
所有代码需先导入Pandas:import pandas as pd,以下是覆盖90%场景的创建方法:
(1)基础创建:列表/元组(默认整数索引)
python
# 列表创建(整数型)
s1 = pd.Series([10, 20, 30, 40])
# 元组创建(字符串型)
s2 = pd.Series(("苹果", "香蕉", "橙子"))
print("s1输出:\n", s1)
# 输出结果:
# 0 10
# 1 20
# 2 30
# 3 40
# dtype: int64
(2)自定义索引+名称(实用场景)
python
# 索引用姓名,名称设为"数学分数"
s3 = pd.Series([95, 88, 92], index=["张三", "李四", "王五"], name="数学分数")
print("s3输出:\n", s3)
# 输出结果:
# 张三 95
# 李四 88
# 王五 92
# Name: 数学分数, dtype: int64
(3)字典创建:key为索引,value为数据
python
score_dict = {"张三": 85, "李四": 90, "王五": 78}
s4 = pd.Series(score_dict, name="英语分数")
print("s4输出:\n", s4)
(4)NumPy数组创建:批量生成数据
需导入NumPy:import numpy as np
python
# 生成0-10的等差数列(步长2)
arr = np.arange(0, 11, 2) # [0,2,4,6,8,10]
s5 = pd.Series(arr, index=[f"第{i}个" for i in range(1, 7)], name="序列值")
print("s5输出:\n", s5)
(5)标量值创建:所有索引对应同一值
python
# 所有用户初始积分都是0
s6 = pd.Series(0, index=["用户1", "用户2", "用户3"], name="初始积分")
print("s6输出:\n", s6)
2.3 创建三大注意点(避坑!)
- 索引长度必须与数据一致:如数据有3个元素,index必须是3个标签,否则报错;
- 避免混合数据类型 :如
[10, "20", True]会自动转为object类型,运算效率大幅降低; - 建议添加name属性:后续作为DataFrame列时,name会直接作为列名,无需额外重命名。
2.4 Series核心属性(必记+实操)
属性通过".+属性名"调用(无括号),基于上文s3(数学分数数据)演示:
python
# 1. 基础属性
print("索引:", s3.index) # 获取所有索引 → Index(['张三','李四','王五'], dtype='object')
print("数据:", s3.values) # 获取数据(NumPy数组) → [95 88 92]
print("名称:", s3.name) # 获取名称 → 数学分数
print("数据类型:", s3.dtype) # 获取类型 → int64
print("形状:", s3.shape) # 数据形状(一维元组) → (3,)
print("数据个数:", s3.size) # 总元素数 → 3
# 2. 实用判断属性
print("是否有缺失值:", s3.hasnans) # 有无NaN → False
print("数据是否唯一:", s3.is_unique) # 有无重复值 → True
print("是否为空:", s3.empty) # 是否空序列 → False
# 3. 属性修改(index/name可整体赋值)
s3.name = "期末数学分数" # 修改名称
s3.index = ["学生1", "学生2", "学生3"] # 修改索引
print("修改后s3:\n", s3)
三、DataFrame:二维表格的四大核心操作
DataFrame是Pandas的"主力",覆盖数据分析全流程,重点掌握创建、属性、索引、方法四大模块。
3.1 DataFrame创建:4种高频方式
(1)字典创建(基础首选)
字典key为列名,value为列数据(列表/元组,长度需一致):
python
data = {
"姓名": ["张三", "李四", "王五", "赵六"],
"年龄": [22, 25, 30, 28],
"城市": ["北京", "上海", "广州", "深圳"],
"薪资": [15000, 18000, 20000, 17000]
}
# 默认整数索引
df1 = pd.DataFrame(data)
# 自定义行索引(员工编号)
df2 = pd.DataFrame(data, index=["员工1", "员工2", "员工3", "员工4"])
print("df2输出:\n", df2)
(2)外部文件读取(实战首选)
处理真实数据必用,支持CSV、Excel、数据库,重点掌握CSV和Excel:
python
# 1. 读取CSV文件(需提前准备"数据.csv")
df_csv = pd.read_csv(
"数据.csv",
header=0, # 第0行作为列名(默认)
index_col=None, # 不将任何列设为行索引
encoding="utf-8" # 中文编码(乱码时换"gbk")
)
# 2. 读取Excel文件(需安装openpyxl:pip install openpyxl)
df_excel = pd.read_excel(
"数据.xlsx",
sheet_name="Sheet1", # 读取的工作表名
usecols=["姓名", "年龄"] # 只读取指定列
)
(3)NumPy数组创建(批量随机数据)
python
import numpy as np
# 生成3行4列的0-100随机整数
arr = np.random.randint(0, 100, size=(3, 4))
df3 = pd.DataFrame(
arr,
columns=["col1", "col2", "col3", "col4"], # 列名
index=[1, 2, 3] # 行索引
)
print("df3输出:\n", df3)
(4)空表创建(逐步添加数据)
适合数据需动态生成的场景:
python
# 先创建空表(只指定列名)
df_empty = pd.DataFrame(columns=["姓名", "年龄"])
# 按行添加数据(loc[行索引])
df_empty.loc[0] = ["张三", 22]
df_empty.loc[1] = ["李四", 25]
print("添加数据后df_empty:\n", df_empty)
3.2 DataFrame核心属性(快速了解数据)
基于上文df2(员工数据)演示:
python
# 1. 索引与列名
print("行索引:", df2.index) # → Index(['员工1','员工2','员工3','员工4'], dtype='object')
print("列名:", df2.columns) # → Index(['姓名','年龄','城市','薪资'], dtype='object')
# 2. 结构与类型
print("数据形状(行×列):", df2.shape) # → (4, 4)
print("总数据个数:", df2.size) # → 16(4×4)
print("每列数据类型:\n", df2.dtypes) # 姓名object,年龄int64等
# 3. 详细信息(排错常用)
print("数据详细信息:\n")
df2.info() # 输出行数、非空值数、内存占用
# 4. 数值统计(仅对int64/float64列生效)
print("数值列统计:\n", df2.describe())
3.3 DataFrame索引操作(导航核心)
索引是DataFrame的"导航系统",重点掌握单级索引 和多级索引。
(1)单级索引:设置与重置
python
# 1. 设置行索引(用"姓名"列作为索引)
df_index1 = df2.set_index("姓名") # 原"姓名"列会删除
df_index2 = df2.set_index("姓名", drop=False) # drop=False:保留原"姓名"列
# 2. 重置索引(恢复默认整数索引)
df_reset1 = df_index2.reset_index() # 原索引转为普通列
df_reset2 = df_index2.reset_index(drop=True) # drop=True:删除原索引
print("设置索引后df_index2:\n", df_index2)
print("重置索引后df_reset1:\n", df_reset1)
(2)多级索引(复杂分组场景)
适合"年份+月份""产品+地区"等多层分类:
python
data_multi = {
"销量": [100, 200, 150, 250],
"营收": [1000, 2000, 1500, 2500]
}
df_multi = pd.DataFrame(
data_multi,
# 多级行索引(年份+月份)
index=[["2024", "2024", "2025", "2025"], ["1月", "2月", "1月", "2月"]],
# 多级列索引(产品+地区)
columns=[["A产品", "A产品", "B产品", "B产品"], ["北京", "上海", "北京", "上海"]]
)
# 给索引命名
df_multi.index.names = ["年份", "月份"]
df_multi.columns.names = ["产品", "地区"]
# 多级索引筛选(用loc)
print("2024年A产品数据:\n", df_multi.loc["2024", "A产品"])
print("2024年1月A产品北京数据:\n", df_multi.loc[("2024", "1月"), ("A产品", "北京")])
3.4 DataFrame高频方法(数据操作)
方法通过".+方法名()`"调用(带括号,可传参数),覆盖数据查看、筛选、清洗、修改。
(1)数据查看
python
# 查看前2行(默认5行)
print("前2行:\n", df2.head(2))
# 查看最后1行
print("最后1行:\n", df2.tail(1))
# 随机查看2行(避免数据顺序影响判断)
print("随机2行:\n", df2.sample(2))
(2)数据筛选
python
# 1. 按列筛选(单列→Series,多列→DataFrame)
print("单列(姓名):\n", df2["姓名"])
print("多列(姓名+薪资):\n", df2[["姓名", "薪资"]])
# 2. 按行筛选(布尔索引)
# 筛选年龄>25的行
print("年龄>25的行:\n", df2[df2["年龄"] > 25])
# 多条件筛选(年龄>25且城市=广州,注意括号)
print("年龄>25且城市=广州:\n", df2[(df2["年龄"] > 25) & (df2["城市"] == "广州")])
# 3. 按标签/位置筛选(loc/iloc,重点!)
# loc:按标签(行名+列名)
print("员工2的薪资:\n", df2.loc["员工2", "薪资"])
# iloc:按位置(0开始的索引,左闭右开)
print("前2行前2列:\n", df2.iloc[0:2, 0:2])
(3)数据清洗(处理缺失值/重复值)
python
import numpy as np
# 复制原数据,避免修改源表
df_clean = df2.copy()
# 手动添加缺失值(员工1薪资设为NaN)
df_clean.loc["员工1", "薪资"] = np.nan
# 1. 缺失值处理
# 删除含缺失值的行(默认how="any":有一个缺失就删)
df_clean.dropna()
# 填充缺失值(薪资用均值填充)
df_clean.fillna({"薪资": df_clean["薪资"].mean()})
# 2. 重复值处理
# 构造重复数据(拼接df2两次)
df_dup = pd.concat([df2, df2])
# 判断每行是否重复(返回布尔值)
print("重复值判断:\n", df_dup.duplicated())
# 删除完全重复的行
df_dup.drop_duplicates()
(4)数据修改(新增/删除/重命名)
python
# 1. 新增列
# 基于薪资计算年终奖(1.2倍)
df2["年终奖"] = df2["薪资"] * 1.2
# 新增固定值列(部门全为"技术部")
df2["部门"] = "技术部"
# 2. 删除列/行
# 删除"部门"列(inplace=True:修改原表)
df2.drop(columns=["部门"], inplace=True)
# 删除"员工4"行
df2.drop(index=["员工4"], inplace=True)
# 3. 重命名列/行
df2.rename(
columns={"年终奖": "年终奖金", "城市": "工作城市"}, # 列重命名
index={"员工1": "EMP101"} # 行重命名
)
print("修改后df2:\n", df2)
3.5 DataFrame核心数据类型(6类常用)
数据类型直接影响运算效率,需掌握"识别+转换",常用类型如下:
| 数据类型 | dtype标识 | 应用场景 | 关键说明 |
|---|---|---|---|
| 整数型 | int64/Int64 | 年龄、ID、数量 | Int64(大写I)支持NaN,避免转为float64 |
| 浮点型 | float64 | 价格、薪资、分数 | 默认支持NaN,可通过downcast优化内存 |
| 字符串型 | string/object | 姓名、城市、描述 | 优先用string类型(比object支持更多字符串方法) |
| 日期时间型 | datetime64[ns] | 注册时间、订单时间 | 必须转换为该类型才能做时间运算(如求间隔) |
| 分类型 | category | 性别、等级(A/B/C)、状态 | 离散值专用,节省80%+内存,分组排序更快 |
| 布尔型 | boolean | 是否转正、是否达标 | boolean(大写B)支持NaN,默认bool不支持 |
数据类型转换(实战核心)
常用astype()(通用)和专用函数(日期用to_datetime()):
python
# 构造示例数据
df_type = pd.DataFrame({
"姓名": ["张三", "李四"],
"年龄": [22, 25], # int64
"薪资": [15000.0, 18000.5], # float64
"注册时间": ["2024-01-01", "2024-02-01"], # object
"性别": ["男", "女"] # object
})
# 1. 基础转换(astype())
# 单个列转换:年龄→float64,性别→category
df_type["年龄"] = df_type["年龄"].astype("float64")
df_type["性别"] = df_type["性别"].astype("category")
# 多个列转换(字典格式)
df_type = df_type.astype({
"薪资": "int64", # 浮点→整数(丢失小数!)
"姓名": "string" # object→string
})
# 2. 专用转换(日期)
# 字符串→日期时间(format指定格式,避免解析错误)
df_type["注册时间"] = pd.to_datetime(df_type["注册时间"], format="%Y-%m-%d")
print("转换后数据类型:\n", df_type.dtypes)
四、总结:Pandas基础核心速记
- 数据结构:Series(一维标签数组)、DataFrame(二维标签表格),Panel极少用;
- Series重点:创建注意索引长度/数据类型/name属性,掌握index/values/dtype等核心属性;
- DataFrame重点 :
- 创建:字典(基础)、外部文件(实战);
- 索引:set_index/reset_index(单级)、MultiIndex(多级);
- 方法:loc/iloc(筛选)、dropna/fillna(缺失值)、drop/rename(修改);
- 数据类型:避免滥用object,日期转datetime64,离散值转category,NaN用Int64/boolean。
所有代码建议手动跑一遍,重点关注"避坑点"(如索引长度、数据类型混合),后续学习分组(groupby)、合并(merge)会更轻松!