Pandas 数据处理基础入门
实验环境 : 华为云 FlexusX 实例 (Ubuntu 24.04, 8vCPU/16GiB)
Pandas 版本 : 2.1.4
实验日期 : 2026-06-29
作者: 腾讯开发者 - 华为云实战系列
目录
- 实验背景
- 环境准备
- [实验1: 数据类型](#实验1: 数据类型)
- [实验2: 数据读取](#实验2: 数据读取)
- [实验3: 数据预览和基本操作](#实验3: 数据预览和基本操作)
- [实验4: 数据选择](#实验4: 数据选择)
- [实验5: 数据增删](#实验5: 数据增删)
- [实验6: 数据填充](#实验6: 数据填充)
- [实验7: 数据可视化](#实验7: 数据可视化)
- 踩坑记录
- 总结
实验背景
Pandas 是 Python 生态中最核心的数据分析库,提供了高性能、易用的数据结构和数据分析工具。本实验在华为云 FlexusX 实例上,通过 7 个递进实验,系统掌握 Pandas 的数据类型、读取、选择、增删、填充和可视化功能。
实验目标
- 理解 Pandas 的 7 种核心数据类型
- 掌握 CSV / 字典 / 数据库等多种数据读取方式
- 熟练使用
head()/tail()/info()/describe()进行数据预览 - 掌握
loc/iloc/ 条件筛选等数据选择方法 - 掌握新增 / 删除行列的操作
- 处理缺失值:固定值填充、前向/后向填充、插值
- 使用 Matplotlib 后端生成 4 种数据可视化图表
环境准备
华为云服务器配置
| 参数 | 值 |
|---|---|
| 实例类型 | FlexusX x2e.8u.16g |
| CPU | 8vCPU |
| 内存 | 16GiB |
| 操作系统 | Ubuntu 24.04 server 64bit |
| 网络 | 5 Mbit/s BGP |
| Python | 3.12.3 |
| Pandas | 2.1.4 |
安装 Pandas
bash
# 更新软件源并安装 Pandas (Ubuntu 24.04)
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq python3-pandas python3-matplotlib python3-seaborn
验证安装
python
import pandas as pd
import numpy as np
import matplotlib
print(pd.__version__) # 2.1.4
print(np.__version__) # 1.26.4
print(matplotlib.__version__) # 3.8.4
实验1: 数据类型 (Data Types)
Pandas 支持多种数据类型,了解它们是数据处理的基础。
1.1 创建不同数据类型的 Series
python
import pandas as pd
import numpy as np
# 整数类型
s_int = pd.Series([1, 2, 3, 4, 5])
print(f"s_int dtype: {s_int.dtype}") # int64
# 浮点类型
s_float = pd.Series([1.1, 2.2, 3.3, 4.4])
print(f"s_float dtype: {s_float.dtype}") # float64
# 字符串类型 (object)
s_str = pd.Series(['apple', 'banana', 'cherry'])
print(f"s_str dtype: {s_str.dtype}") # object
# 布尔类型
s_bool = pd.Series([True, False, True, True])
print(f"s_bool dtype: {s_bool.dtype}") # bool
# 日期时间类型
s_datetime = pd.Series(pd.to_datetime(['2024-01-01', '2024-02-01', '2024-03-01']))
print(f"s_datetime dtype: {s_datetime.dtype}") # datetime64[ns]
输出:
s_int dtype: int64
s_float dtype: float64
s_str dtype: object
s_bool dtype: bool
s_datetime dtype: datetime64[ns]
1.2 DataFrame 各列的数据类型
python
df = pd.read_csv('/tmp/employees.csv')
print(df.dtypes)
输出:
name object
age int64
city object
salary float64
hire_date object
department object
dtype: object
1.3 数据类型转换
python
# 将 age 列从 int64 转换为 float64
df['age'] = df['age'].astype('float64')
print('age列转换为float64:', df['age'].dtype)
# 将 city 列转换为分类类型 (节省内存)
df['city'] = df['city'].astype('category')
print('city列转换为category:', df['city'].dtype)
print('分类唯一值:', df['city'].cat.categories.tolist())
输出:
age列转换为float64: float64
city列转换为category: category
分类唯一值: ['上海', '北京', '广州', '深圳']
Pandas 常用数据类型对照表
| 类型 | 说明 | 示例 |
|---|---|---|
int64 |
64位整数 | 1, 2, 3 |
float64 |
64位浮点数 | 1.1, 2.2 |
object |
字符串/混合类型 | 'hello', 'world' |
bool |
布尔值 | True, False |
datetime64[ns] |
日期时间 | 2024-01-01 |
category |
分类变量 | 'A', 'B', 'C' |
timedelta[ns] |
时间差 | days=1 |
实验2: 数据读取 (Data Reading)
2.1 读取 CSV 文件
python
import pandas as pd
# 读取员工数据
df = pd.read_csv('/tmp/employees.csv')
print(f'数据形状: {df.shape}')
print(f'列名: {list(df.columns)}')
print('\n前5行数据:')
print(df.head())
输出:
数据形状: (20, 6)
列名: ['name', 'age', 'city', 'salary', 'hire_date', 'department']
前5行数据:
name age city salary hire_date department
0 张三 28 北京 15000.0 2020-03-15 技术部
1 李四 32 上海 18000.0 2019-07-20 市场部
2 王五 25 北京 12000.0 2021-01-10 技术部
3 赵六 35 深圳 22000.0 2018-11-05 财务部
4 钱七 29 上海 16000.0 2020-09-18 市场部
2.2 读取时指定参数
python
# 将 hire_date 列解析为日期类型
df2 = pd.read_csv('/tmp/employees.csv', index_col=0, parse_dates=['hire_date'])
print('设置hire_date为日期类型:')
print(df2.dtypes)
输出:
设置hire_date为日期类型:
age int64
city object
salary float64
hire_date datetime64[ns]
department object
dtype: object
2.3 从字典创建 DataFrame
python
data = {'name': ['Alice', 'Bob', 'Charlie'], 'score': [85, 92, 78]}
df3 = pd.DataFrame(data)
print(df3)
输出:
name score
0 Alice 85
1 Bob 92
2 Charlie 78
read_csv 常用参数
| 参数 | 说明 |
|---|---|
filepath_or_buffer |
文件路径或 URL |
sep |
分隔符,默认 , |
header |
列名行,默认 0 (第一行) |
index_col |
用作索引的列 |
usecols |
选择读取的列 |
dtype |
指定列的数据类型 |
parse_dates |
解析为日期的列 |
na_values |
识别为 NaN 的值 |
实验3: 数据预览和基本操作
3.1 数据预览
python
# 前3行
print(df.head(3))
# 后3行
print(df.tail(3))
# 数据信息
print(df.info())
# 统计描述
print(df.describe())
输出:
[前3行]
name age city salary hire_date department
0 张三 28 北京 15000.0 2020-03-15 技术部
1 李四 32 上海 18000.0 2019-07-20 市场部
2 王五 25 北京 12000.0 2021-01-10 技术部
[后3行]
name age city salary hire_date department
17 王二十 23 广州 11000.0 2022-01-05 人事部
18 李二一 31 NaN 18500.0 2019-08-22 市场部
19 赵二二 37 深圳 26000.0 2016-12-30 技术部
[数据信息]
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 20 entries, 0 to 19
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 name 20 non-null object
1 age 20 non-null int64
2 city 18 non-null object
3 salary 19 non-null float64
4 hire_date 20 non-null object
5 department 20 non-null object
dtypes: float64(1), int64(1), object(4)
memory usage: 1.1+ KB
[统计描述]
age salary
count 20.000000 19.000000
mean 30.700000 18184.210526
std 4.878524 4497.562693
min 23.000000 11000.000000
25% 26.750000 14500.000000
50% 30.500000 18000.000000
75% 34.250000 21500.000000
max 40.000000 26000.000000
3.2 基本操作
python
# 列访问
print(df['salary'].head())
# 新增列 (奖金 = 薪资 × 10%)
df['bonus'] = df['salary'] * 0.1
print(df[['name', 'salary', 'bonus']].head())
输出:
[访问salary列 (前5个)]
0 15000.0
1 18000.0
2 12000.0
3 22000.0
4 16000.0
Name: salary, dtype: float64
[新增bonus列]
name salary bonus
0 张三 15000.0 1500.0
1 李四 18000.0 1800.0
2 王五 12000.0 1200.0
3 赵六 22000.0 2200.0
4 钱七 16000.0 1600.0
实验4: 数据选择 (Data Selection)
4.1 列选择
python
# 选择单列
print(df[['name', 'salary']].head())
4.2 行选择 - loc (标签索引)
python
# 选择行标签 0~2,列 name/city/salary
print(df.loc[0:2, ['name', 'city', 'salary']])
输出:
name city salary
0 张三 北京 15000.0
1 李四 上海 18000.0
2 王五 北京 12000.0
4.3 行选择 - iloc (位置索引)
python
# 选择前2行,前3列
print(df.iloc[0:2, 0:3])
输出:
name age city
0 张三 28 北京
1 李四 32 上海
4.4 条件选择
python
# 筛选薪资 > 20000 的员工
print(df[df['salary'] > 20000][['name', 'salary']])
输出:
name salary
3 赵六 22000.0
5 孙八 25000.0
11 赵十四 23000.0
14 周十七 21000.0
16 郑十九 24000.0
19 赵二二 26000.0
4.5 多条件选择
python
# 北京且薪资 > 15000
print(df[(df['city'] == '北京') & (df['salary'] > 15000)][['name', 'city', 'salary']])
输出:
name city salary
5 孙八 北京 25000.0
16 郑十九 北京 24000.0
loc vs iloc 对比
| 方法 | 索引类型 | 示例 |
|---|---|---|
loc |
标签索引 | df.loc[0:2] 包含标签 2 |
iloc |
位置索引 | df.iloc[0:2] 不包含位置 2 |
at |
单个标签 | df.at[0, 'name'] |
iat |
单个位置 | df.iat[0, 0] |
实验5: 数据增删 (Data Addition/Deletion)
5.1 新增列
python
df['level'] = ['P6', 'P7', 'P5', 'P8', 'P7', 'P9', 'P5', 'P7', 'P6', 'P8', 'P5', 'P9', 'P6', 'P5', 'P8', 'P7', 'P9', 'P4', 'P7', 'P9']
print(df[['name', 'level']].head())
5.2 新增行
python
new_row = pd.DataFrame({
'name': ['新员一'], 'age': [26], 'city': ['杭州'],
'salary': [16000], 'hire_date': ['2023-01-01'], 'department': ['技术部']
})
df = pd.concat([df, new_row], ignore_index=True)
print('新增行后数据形状:', df.shape) # (21, 7)
5.3 删除列
python
df_drop = df.copy()
df_drop = df_drop.drop('level', axis=1)
print('删除level列后列名:', list(df_drop.columns))
5.4 删除行
python
df_drop_rows = df.drop([0, 1]).reset_index(drop=True)
print('删除前2行后形状:', df_drop_rows.shape) # (19, 7)
实验6: 数据填充 (Data Filling)
6.1 查找缺失值
python
print('各列缺失值数量:')
print(df.isnull().sum())
输出:
各列缺失值数量:
name 0
age 0
city 2
salary 1
hire_date 0
department 0
dtype: int64
6.2 填充缺失值 - 固定值
python
df_fill = df.copy()
# 用平均值填充 age 的缺失值
df_fill['age'] = df_fill['age'].fillna(df_fill['age'].mean())
# 用 '未知' 填充 city 的缺失值
df_fill['city'] = df_fill['city'].fillna('未知')
# 用中位数填充 salary 的缺失值
df_fill['salary'] = df_fill['salary'].fillna(df_fill['salary'].median())
print('填充后缺失值:')
print(df_fill.isnull().sum())
输出:
填充后缺失值:
name 0
age 0
city 0
salary 0
hire_date 0
department 0
dtype: int64
6.3 填充缺失值 - 前向/后向填充
python
df_ffill = pd.DataFrame({'a': [1, None, None, 4, None, 6]})
print('使用前向填充:')
print(df_ffill['a'].ffill()) # 等价于 fillna(method='ffill')
输出:
使用前向填充:
0 1.0
1 1.0
2 1.0
3 4.0
4 4.0
5 6.0
Name: a, dtype: float64
6.4 插值填充
python
df_interp = pd.DataFrame({'value': [10, None, 30, None, 50]})
df_interp['value'] = df_interp['value'].interpolate()
print(df_interp)
输出:
value
0 10.0
1 20.0
2 30.0
3 40.0
4 50.0
缺失值处理策略
| 方法 | 函数 | 适用场景 |
|---|---|---|
| 删除缺失行 | df.dropna() |
缺失比例很小 |
| 固定值填充 | df.fillna(value) |
已知填充值 |
| 均值/中位数填充 | df.fillna(df.mean()) |
数值型数据 |
| 众数填充 | df.fillna(df.mode()) |
分类型数据 |
| 前向填充 | df.ffill() |
时间序列数据 |
| 后向填充 | df.bfill() |
时间序列数据 |
| 插值填充 | df.interpolate() |
连续数值数据 |
实验7: 数据可视化 (Data Visualization)
7.1 柱状图 - 各部门人数
python
import matplotlib
matplotlib.use('Agg') # 使用非交互式后端
import matplotlib.pyplot as plt
df = pd.read_csv('/tmp/employees.csv')
dept_counts = df['department'].value_counts()
fig, ax = plt.subplots(figsize=(8, 5))
dept_counts.plot(kind='bar', ax=ax)
ax.set_title('Department Distribution')
ax.set_ylabel('Count')
plt.tight_layout()
plt.savefig('/tmp/dept_bar.png')
print('柱状图已保存到 /tmp/dept_bar.png')
print(dept_counts)
输出:
department
技术部 9
市场部 5
财务部 3
人事部 3
Name: count, dtype: int64

7.2 直方图 - 薪资分布
python
fig, ax = plt.subplots(figsize=(8, 5))
df['salary'].plot(kind='hist', bins=10, ax=ax)
ax.set_title('Salary Distribution')
ax.set_xlabel('Salary')
plt.tight_layout()
plt.savefig('/tmp/salary_hist.png')
print('直方图已保存到 /tmp/salary_hist.png')

7.3 箱线图 - 各市薪资
python
fig, ax = plt.subplots(figsize=(8, 5))
df.boxplot(column='salary', by='city', ax=ax)
plt.title('Salary by City')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('/tmp/salary_box.png')
print('箱线图已保存到 /tmp/salary_box.png')

7.4 折线图 - 月度销售趋势
python
sales = pd.read_csv('/tmp/sales.csv')
monthly = sales.groupby('month')['sales'].sum()
print(monthly)
fig, ax = plt.subplots(figsize=(8, 5))
monthly.plot(kind='line', marker='o', ax=ax)
ax.set_title('Monthly Sales Trend')
ax.set_ylabel('Sales')
plt.tight_layout()
plt.savefig('/tmp/sales_line.png')
print('折线图已保存到 /tmp/sales_line.png')
输出:
month
2024-01 290000
2024-02 325000
2024-03 315000
2024-04 347000
Name: sales, dtype: int64

Pandas 内置绘图函数
| 图表类型 | 函数 | 说明 |
|---|---|---|
| 折线图 | df.plot(kind='line') |
趋势分析 |
| 柱状图 | df.plot(kind='bar') |
分类比较 |
| 直方图 | df.plot(kind='hist') |
分布分析 |
| 箱线图 | df.boxplot() |
离群值检测 |
| 散点图 | df.plot(kind='scatter') |
相关性分析 |
| 饼图 | df.plot(kind='pie') |
占比分析 |
| 面积图 | df.plot(kind='area') |
累积趋势 |
踩坑记录
坑1: fillna(method='ffill') 已弃用
错误信息:
FutureWarning: DataFrame.fillna with 'method' is deprecated and will raise in a future version.
解决方案:
python
# 旧写法 (已弃用)
df.fillna(method='ffill')
# 新写法 (推荐)
df.ffill()
df.bfill()
坑2: Matplotlib 中文显示乱码
问题: 在 Ubuntu Server 上生成图表时,中文显示为方框。
解决方案:
python
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['DejaVu Sans', 'SimHei', 'WenQuanYi Micro Hei']
plt.rcParams['axes.unicode_minus'] = False
坑3: info() 输出不直接显示
问题 : df.info() 打印到 stdout,无法直接获取字符串。
解决方案:
python
# 方法1: 重定向到缓冲区
import io
buffer = io.StringIO()
df.info(buf=buffer)
info_str = buffer.getvalue()
# 方法2: 使用 df.memory_usage(deep=True)
总结
通过本实验,在华为云 FlexusX 实例上完成了 Pandas 数据处理的 7 个核心实验:
- 数据类型 : 掌握
int64/float64/object/bool/datetime64[ns]/category等类型及转换方法 - 数据读取 : 熟练使用
read_csv读取 CSV 文件,并掌握常用参数 - 数据预览 : 使用
head()/tail()/info()/describe()快速了解数据 - 数据选择 : 掌握
loc(标签) /iloc(位置) / 条件筛选三种选择方式 - 数据增删 : 使用
assign/concat新增行列,使用drop删除行列 - 数据填充: 处理缺失值的 4 种策略:固定值、前向/后向填充、插值
- 数据可视化: 使用 Matplotlib 后端生成柱状图、直方图、箱线图、折线图
后续学习方向
- 数据合并 :
merge/join/concat - 数据透视 :
pivot_table/groupby - 时间序列 :
resample/rolling/shift - 高性能优化 :
eval/query/Categorical - 大数据处理 :
Dask/Modin(兼容 Pandas API)
附录: 实验数据说明
employees.csv (员工数据)
| 列名 | 类型 | 说明 |
|---|---|---|
| name | object | 员工姓名 |
| age | int64 | 年龄 |
| city | object | 工作城市 |
| salary | float64 | 月薪 |
| hire_date | object | 入职日期 |
| department | object | 所属部门 |
sales.csv (销售数据)
| 列名 | 类型 | 说明 |
|---|---|---|
| month | object | 月份 |
| product | object | 产品名称 |
| category | object | 产品类别 |
| sales | int64 | 销售额 |
| profit | int64 | 利润 |
实验服务器 : 华为云 FlexusX x2e.8u.16g (120.46.31.149)
实验日期 : 2026-06-29
完整代码 : GitHub 仓库链接
下一篇: 《Matplotlib 数据可视化进阶实战》