文章目录
-
- 构建数据
-
- 清洗数据示例
-
- 清洗数据-1、创建原始数据
- [2、使用 Pandas 进行数据清洗](#2、使用 Pandas 进行数据清洗)
- 3、总结下这段代码干了什么
- 读取数据常用方法
-
- [读取数据 read_json() 读取json字符串](#读取数据 read_json() 读取json字符串)
- [读取数据 read_json() 读取json文件](#读取数据 read_json() 读取json文件)
- [读取数据 read_json() 读取jsonl字符串](#读取数据 read_json() 读取jsonl字符串)
- [读取数据 read_json() 读取jsonl文件](#读取数据 read_json() 读取jsonl文件)
- pandas支持复杂结构的json吗?
- json_normalize
Pandas 是 Python 中用于数据分析和数据处理的"瑞士军刀",是目前数据科学领域最核心的工具库之一。必须掌握。
构建数据
构建数据主要通过DataFrame来实现。
构建数据-列向导
python
import pandas as pd
data = {
'姓名': ['张三', '李四', '王五'],
'年龄': [25, 30, 35],
'城市': ['北京', '上海', '广州']
}
df = pd.DataFrame(data)
print(df)
输出结果:
python
姓名 年龄 城市
0 张三 25 北京
1 李四 30 上海
2 王五 35 广州
这么理解就好理解了:
姓名是列名,张三等是列下面的数据,每一列的行数要相等。

构建数据-行向导
因为行数据本身没有列名,所以构建时需要显示指定列名(columns)。
python
import pandas as pd
# 每一组中括号代表一行数据
data = [
['张三', 25, '北京'],
['李四', 30, '上海'],
['王五', 35, '广州']
]
# 必须显式指定列名
df = pd.DataFrame(data, columns=['姓名', '年龄', '城市'])
print(df)
输出结果:
python
姓名 年龄 城市
0 张三 25 北京
1 李四 30 上海
2 王五 35 广州
构建数据-矩阵导向
python
import pandas as pd
import numpy as np
# 生成一个 3行4列 的随机数矩阵
arr = np.random.randn(3, 4)
df = pd.DataFrame(arr, columns=['A', 'B', 'C', 'D'])
print(df)
输出结果:
python
A B C D
0 0.383721 0.299960 -0.866526 -1.889621
1 -0.418412 -0.084870 -1.008183 0.075037
2 -0.181221 1.113219 -1.296714 1.225547
构建数据-记录导向
python
import pandas as pd
data = [
{'姓名': '张三', '年龄': 25, '城市': '北京'},
{'姓名': '李四', '年龄': 30, '城市': '上海'},
# 注意:如果某一行缺少某个字段(比如王五没写城市),Pandas 会自动填 NaN
{'姓名': '王五', '年龄': 35}
]
df = pd.DataFrame(data)
print(df)
输出结果:
python
姓名 年龄 城市
0 张三 25 北京
1 李四 30 上海
2 王五 35 NaN
构建数据-总结
一句话,纯数据需要指定名,其他都不需要指定列名。
| 数据 | 示例 | 要 |
|---|---|---|
| 纯数组 | ['张三', 25, '北京'] |
需要指定列名 |
| 列名+数组 | '姓名': ['张三', '李四', '王五'] |
无需指定列名 |
| 键值对 | {'姓名': '张三', '年龄': 25, '城市': '北京'} |
无需指定列名 |
读取外部文件
| 形式 | 代码示例 | 说明 |
|---|---|---|
| CSV 文件 | pd.read_csv('data.csv') |
最通用的文本格式 |
| Excel 文件 | pd.read_excel('data.xlsx') |
读取办公文档 |
| Parquet 文件 | pd.read_parquet('data.parquet') |
大数据/高性能场景首选 |
| SQL 数据库 | pd.read_sql(query, conn) |
从 MySQL/PostgreSQL 读取 |
清洗数据示例
清洗数据-1、创建原始数据
新建sales_raw.xlsx文件,内容复制进去:
| 订单ID | 门店名称 | 销售日期 | 销售额 | 客户等级 | 备注 |
|---|---|---|---|---|---|
| 1001 | 北京店 | 2023-01-01 | 2500 | VIP | 无 |
| 1002 | 上海 分店 | 2023-01-01 | 3000 | vip | |
| 1003 | 广州门店 | 2023/01/02 | 1800 | Normal | 促销订单 |
| 1004 | 深圳店 | 2023-01-02 | 2200 | NORMAL | 重要客户 |
| 1001 | 北京店 | 2023-01-01 | 2500 | VIP | 无 |
| 1005 | 杭州分店 | 2023-01-03 | High | ||
| 1006 | 成都 门店 | 2023-01-03 | 2800 | normal | |
| 1007 | 武汉店 | 2023-01-04 | 3100 | 新客户 | |
| 西安分店 | 2023-01-04 | 2400 | VIP |
该数据是有脏数据的。
1、重复数据:订单ID为 1001 的记录重复出现。
2、缺失值:第7行"客户等级"为空,第5行"销售额"为空,第9行"订单ID"为空。
3、格式不一致:
- 门店名称:有"店"、"分店"、"门店"等多种写法,且包含空格(如"上海 分店")。
- 客户等级:VIP、vip、High、Normal、normal 大小写和命名不统一。
- 销售日期:存在 2023-01-01 和 2023/01/02 两种格式。
4、异常空格:"上海 分店"、"成都 门店"中存在多余空格。
5、字段冗余:"备注"列存在大量空值,可能无实际用途。
2、使用 Pandas 进行数据清洗
代码:
python
import pandas as pd
# 1. 读取原始数据
df = pd.read_excel("sales_raw.xlsx")
print("原始数据形状:", df.shape)
print("前5行数据:")
print(df.head())
# 2. 处理缺失值
# 填充销售额缺失值为该列均值(数值型)
df['销售额'] = df['销售额'].fillna(df['销售额'].mean())
# 填充客户等级缺失值为 'Unknown'(分类变量)
df['客户等级'] = df['客户等级'].fillna('Unknown')
# 删除订单ID为空的整行(关键字段缺失)
df = df.dropna(subset=['订单ID'])
# 3. 去除重复项(基于订单ID)
df = df.drop_duplicates(subset=['订单ID'], keep='first')
# 4. 标准化文本字段
# 清洗门店名称:去除空格、统一后缀为"店"
df['门店名称'] = df['门店名称'].str.replace(' ', '').str.replace('分店|门店', '店', regex=True)
# 统一客户等级:转为大写并映射为标准类别
level_map = {'VIP': 'VIP', 'HIGH': 'High', 'NORMAL': 'Normal', 'UNKNOWN': 'Unknown'}
df['客户等级'] = df['客户等级'].str.upper().map(level_map)
# 5. 统一日期格式
df['销售日期'] = pd.to_datetime(df['销售日期'], errors='coerce')
# 6. 删除冗余列(如无用的备注)
df = df.drop(columns=['备注'], errors='ignore')
# 7. 数据类型优化
df['订单ID'] = df['订单ID'].astype(int)
df['销售额'] = df['销售额'].round(2)
# 8. 查看清洗后结果
print("\n清洗后数据形状:", df.shape)
print("清洗后数据:")
print(df)
# 9. 保存清洗后数据
df.to_excel("sales_cleaned.xlsx", index=False)
部分输出结果:
python
清洗后数据形状: (7, 5)
清洗后数据:
订单ID 门店名称 销售日期 销售额 客户等级
0 1001 北京店 2023-01-01 2500.0 VIP
1 1002 上海店 2023-01-01 3000.0 VIP
2 1003 广州店 2023-01-02 1800.0 Normal
3 1004 深圳店 2023-01-02 2200.0 Normal
5 1005 杭州店 2023-01-03 2537.5 High
6 1006 成都店 2023-01-03 2800.0 Normal
7 1007 武汉店 2023-01-04 3100.0 Unknown
注:销售额 缺失值被填充为均值 2566.67,客户等级 空值标记为 Unknown,所有文本和日期均已标准化。
3、总结下这段代码干了什么
简单来说,刚才那段代码主要干了 4 件"大扫除"的事情,就像整理一个乱糟糟的房间一样:
🗑️ 扔垃圾(处理缺失值)
问题: 表格里有些地方是空的。比如有的行没有"销售额",有的行没有"客户等级"。计算机没法计算空的东西。
怎么修的:
填空缺: 对于"销售额",我们算出其他所有订单的平均数,把空缺填上(或者填0)。对于"客户等级",填上"未知"。
删废行: 如果一行数据连最重要的"订单ID"都没有,那这行数据就彻底废了,直接整行删除。
对应代码: fillna (填充), dropna (删除)
✂️ 剪重复(去除重复项)
问题: "订单1001"在表里出现了两次,内容一模一样。这可能是复制粘贴时手抖多粘了一次。如果不删掉,算总销售额时就会算重。
怎么修的:
告诉电脑:"盯着'订单ID'这一列看,如果发现两个一样的ID,只保留第一个,把后面重复的统统删掉。"
对应代码: drop_duplicates
📏 立规矩(标准化格式)
这是最繁琐的一步,主要是为了统一"写法"。
问题 A(名字乱): 有的叫"上海 分店"(带空格),有的叫"广州门店"(后缀不一样)。
怎么修:
先把所有空格删掉(变成"上海分店")。
再把所有的"分店"、"门店"全部替换成统一的"店"(变成"上海店")。
问题 B(等级乱): 有的是大写"VIP",有的是小写"vip",还有"Normal"。
怎么修:
全部强制转换成大写(VIP, NORMAL)。
建立一个对照表,把它们映射成统一的标准词。
对应代码: .str.replace, .str.upper, .map
🕵️♂️ 抓内鬼(修正数据类型)
问题: 在Excel里,"2023-01-01"有时候会被当成普通的文字(字符串),而不是真正的日期。这样你就没法算"这一天距离今天过了多久"。
怎么修的:
强制把"销售日期"这一列刷上一层"时间滤镜",告诉电脑:"别把它当文字,这是时间!"这样以后就能进行时间计算了。
对应代码: pd.to_datetime
读取数据常用方法
| 类别 | 文件格式 | 读取函数 | 写入函数 |
|---|---|---|---|
| 文本/表格 | CSV / TSV | pd.read_csv() |
df.to_csv() |
| Excel (.xls, .xlsx) | pd.read_excel() |
df.to_excel() |
|
| JSON | pd.read_json() |
df.to_json() |
|
| HTML (网页表格) | pd.read_html() |
df.to_html() |
|
| 高性能/二进制 | Parquet | pd.read_parquet() |
df.to_parquet() |
| HDF5 | pd.read_hdf() |
df.to_hdf() |
|
| Pickle (Python专用) | pd.read_pickle() |
df.to_pickle() |
|
| Feather | pd.read_feather() |
df.to_feather() |
|
| 其他/统计 | SQL 数据库 | pd.read_sql() |
df.to_sql() |
| Stata / SAS / SPSS | pd.read_stata() 等 |
df.to_stata() |
|
| XML | pd.read_xml() |
df.to_xml() |
读取数据 read_json() 读取json字符串
1、创建read_json_from_string.py,代码:
python
import pandas as pd
json_data = '''
[
{"姓名": "张三", "年龄": 25, "城市": "北京"},
{"姓名": "李四", "年龄": 30, "城市": "上海"},
{"姓名": "王五", "年龄": 28, "城市": "深圳"}
]
'''
# 2. 使用 orient='records' 读取
df = pd.read_json(json_data, orient='records')
print("--- 示例1:records 格式读取结果 ---")
print(df)
读取数据 read_json() 读取json文件
1、创建data.json,内容:
json
[
{"姓名": "张三", "城市": "北京"},
{"姓名": "李四", "年龄": 30, "城市": "上海"}
]
2、创建read_json_from_file.py,代码:
python
import pandas as pd
# 直接把文件路径 'data.json' 传给 read_json,并指定 orient='records'
df = pd.read_json('data.json',orient='records')
print(df)
读取数据 read_json() 读取jsonl字符串
注:读取jsonl的时候要加lines=True表示这是个jsonl文件,要按行读取。
python
import pandas as pd
jsonl_data = '''
{"姓名": "张三", "年龄": 25, "城市": "北京"}
{"姓名": "李四", "年龄": 30, "城市": "上海"}
{"姓名": "王五", "年龄": 28, "城市": "深圳"}
'''
# 2. 使用 lines=True 告诉 pandas 这是按行分隔的 JSON
df = pd.read_json(jsonl_data, lines=True,orient='records')
print("--- JSONL 字符串读取结果 ---")
print(df)
读取数据 read_json() 读取jsonl文件
1、创建data.jsonl,内容:
json
{"姓名": "张三", "年龄": 25, "城市": "北京"}
{"姓名": "李四", "年龄": 30, "城市": "上海"}
{"姓名": "王五", "年龄": 28, "城市": "深圳"}
代码:
python
import pandas as pd
df = pd.read_json('data.jsonl', lines=True,orient='records')
print("--- JSONL 字符串读取结果 ---")
print(df)
orient='records'是什么意思?
读取和转换的时候,显示的指定,请按照标准的Key-Value(键值对)格式来处理每一条数据记录。
pandas支持复杂结构的json吗?
最好是行列结构,如果比较复杂,需要结合其他手法,如json_normalize()等。
json_normalize
json_normalize直接拍扁
python
import pandas as pd
from pandas import json_normalize
data = {
"id": 1,
"name": "Alice",
"info": {"age": 25, "city": "Beijing"}
}
# 直接展平
df = json_normalize(data)
print(df)
# 输出列名: id, name, info.age, info.city
json_normalize-结合record_path、meta
record_path(指定列表在哪里)和 meta(保留外层信息):
python
from pandas import json_normalize
data = [
{
"user_id": 101,
"profile": {"name": "Bob"},
"orders": [
{"product": "Book", "price": 20},
{"product": "Pen", "price": 2}
]
}
]
# record_path: 指向那个"列表"字段,这会让每一行变成一个订单
# meta: 把上层的 ID 和名字"提"出来,拼接到每一行
df = json_normalize(
data,
record_path='orders',
meta=['user_id', ['profile', 'name']] # 嵌套字段要用列表表示路径
)
print(df)
输出结果:
python
product price user_id profile.name
0 Book 20 101 Bob
1 Pen 2 101 Bob