数据组合与合并:Pandas 数据整合全指南

在进行数据分析之前,数据清洗与整合是关键步骤。

遵循“整洁数据”(Tidy Data)原则:

  • 每个观测值占一行
  • 每个变量占一列
  • 每种观测单元构成一张独立的表格

整理好数据后,常常需要将多个数据集组合起来,才能回答复杂问题。


一、连接数据(Concatenation)

当多个数据集结构相似(列名一致或相近),可以使用 pd.concat() 将它们按行或列方向拼接。

1. 添加行:DataFrame 连接

import pandas as pd# 加载多个结构相似的 CSV 文件
df1 = pd.read_csv('data/demo1.csv')
df2 = pd.read_csv('data/demo2.csv')
df3 = pd.read_csv('data/demo3.csv')# 沿行方向(垂直)连接
row_concat = pd.concat([df1, df2, df3], ignore_index=True)  # 重置索引
print(row_concat)

参数说明:

  • ignore_index=True:重新生成从 0 开始的整数索引,避免重复行标签。
  • 默认 axis=0 表示按行连接(上下拼接)。

2. 添加行:DataFrame 与 Series 连接

df1 = pd.read_csv('data/demo1.csv')
new_series = pd.Series(['n1', 'n2', 'n3', 'n4'], index=['A', 'B', 'C', 'D'])  # 推荐指定索引# 错误方式(不推荐):
# pd.concat([df1, new_series])  # Series 被当作新列添加,造成 NaN 填充# 正确方式:将 Series 转为 DataFrame 再连接
new_row_df = pd.DataFrame([new_series], index=['new_row'])  # 包装成一行的 DataFrame
result = pd.concat([df1, new_row_df], ignore_index=False)

关键点:

  • 直接 concat([df, series]) 会尝试按列对齐,导致 Series 成为新列,原数据缺失处填 NaN
  • 应先将 Series 转换为单行 DataFrame,并确保其 index 与目标 DataFrame 的列名匹配。

3. 添加行:使用 append() 方法(已弃用,建议用 concat)

注意:DataFrame.append() 方法在 Pandas 1.4+ 中已被 弃用(deprecated),官方推荐使用 pd.concat() 替代。

旧写法(不推荐):

# 已弃用
new_row = {'A': 'n1', 'B': 'n2', 'C': 'n3', 'D': 'n4'}
df1 = df1.append(new_row, ignore_index=True)

新写法(推荐):

new_row_df = pd.DataFrame([{'A': 'n1', 'B': 'n2', 'C': 'n3', 'D': 'n4'}])
df1 = pd.concat([df1, new_row_df], ignore_index=True)

4. 添加行:重置索引

当多次连接后,行索引可能出现重复或无序:

result = pd.concat([df1, df2, df3])
result = result.reset_index(drop=True)  # 丢弃原索引,生成新整数索引

建议:在垂直连接时始终使用 ignore_index=True 或后续调用 reset_index(drop=True)


5. 添加列:使用 concat()

水平连接(axis=1)可实现列拼接:

col_concat = pd.concat([df1, df2], axis=1)  # 按列拼接(左右)

注意:

  • 默认按行索引对齐,若索引不一致会导致 NaN
  • 若两个 DataFrame 行数不同但索引相同,也能对齐。

6. 添加列:直接赋值(最常用)

# 添加标量(广播)
df1['new_col'] = 0# 添加列表或数组(长度需匹配)
df1['new_col'] = [1, 2, 3, 4]# 添加 Series(按索引自动对齐)
s = pd.Series([10, 20, 30, 40], index=df1.index)
df1['new_col'] = s

这是最简洁高效的方式,适用于大多数场景。


7. 添加列:重置索引的影响

如果 Series 的索引与 DataFrame 不一致,直接赋值可能导致 NaN

s = pd.Series([10, 20, 30, 40], index=[0, 1, 2, 3])
df1['new_col'] = s  # 若 df1 索引为 [0,1,2,3],则正常;否则部分为 NaN

解决方案:

  • 使用 .values 强制忽略索引:
    df1['new_col'] = s.values  # 忽略索引,按顺序赋值
    
  • 或先对齐索引:s.reindex(df1.index)

二、合并多个数据集(Merge & Join)

当数据集之间有共同键(key),但结构不同(如主表+属性表),应使用 mergejoin

方法类型用途对齐方式默认连接类型
pd.concat()函数拼接多个对象(行/列)按索引对齐外连接(outer)
DataFrame.join()方法水平合并多个 DataFrame左表列/行索引 vs 右表行索引左连接(left)
pd.merge()函数灵活合并两个 DataFrame基于列或索引内连接(inner)

1. pd.merge():最灵活的合并方式

left = pd.DataFrame({'key': ['K0', 'K1', 'K2'],'A': ['A0', 'A1', 'A2']
})right = pd.DataFrame({'key': ['K0', 'K1', 'K3'],'B': ['B0', 'B1', 'B3']
})# 基于列 'key' 合并
merged = pd.merge(left, right, on='key', how='inner')

参数详解:

  • on:指定连接键(列名)
  • how:连接方式
    • 'inner':交集(默认)
    • 'outer':并集
    • 'left':保留左表所有行
    • 'right':保留右表所有行
  • left_on, right_on:左右表键名不同时使用
  • left_index=True, right_index=True:基于索引合并

示例:不同列名合并

pd.merge(left, right, left_on='key', right_on='key_r', how='outer')

2. DataFrame.join():基于索引的便捷合并

result = left.join(right.set_index('key'), on='key', how='left')
# 或者 right 的索引已经是 'key'
# result = left.join(right, on='key')

特点:

  • 默认以左表为基准how='left'
  • 通常用于:主表 + 多个属性表(如公司信息 + 股价、行业等)
  • 支持多表连接:df.join([df2, df3, df4])

注意:join() 默认是左连接,而 merge() 默认是内连接


3. concat() vs merge() vs join() 对比总结

功能concat()merge()join()
是否支持多对象支持多个仅两个支持多个
连接方向行或列仅列(水平)仅列(水平)
对齐依据索引列或索引左表列/索引 vs 右表索引
默认连接方式outerinnerleft
典型用途日志文件合并、时间序列拼接主键关联表(如订单+用户)属性扩展(如 ID + 特征)

三、常见实践建议

推荐流程:

  1. 清理单个数据集 → 遵循整洁数据原则
  2. 统一列名与数据类型
  3. 根据关系选择合并方式:
    • 结构相同 → pd.concat()
    • 有公共键 → pd.merge()df.join()
  4. 合并后检查:
    • 行数是否合理?
    • 是否出现意外的 NaN
    • 索引是否需要重置?

常见错误避免:

  • 忘记 ignore_index=True 导致索引重复
  • 直接 concat(df, series) 而未包装成 DataFrame
  • 使用已弃用的 .append()
  • merge 时未指定 on,导致笛卡尔积
  • 忽视 how 参数,丢失数据(如默认 inner 丢掉不匹配行)

四、总结

数据整合三剑客

1. pd.concat()
  • 用途:拼接多个对象(行/列)
  • axis=0: 上下拼(常用)
  • axis=1: 左右拼
  • ignore_index=True 重置索引
2. pd.merge()
  • 用途:基于列或索引合并两个表
  • on=‘key’: 指定连接列
  • how: inner, outer, left, right
  • 最灵活,推荐用于主键关联
3. df.join()
  • 用途:基于索引合并多个表
  • 默认左连接
  • 常用于主表 + 多个属性表

Tip: 优先使用 concatmergejoin 适合索引对齐场景。


五、补充

1. 合并时处理重复列名(suffixes 参数)

当两个 DataFrame 有相同列名但不是连接键时,mergejoin 会自动添加后缀避免冲突。

left = pd.DataFrame({'key': ['K0', 'K1'], 'value': [1, 2]})
right = pd.DataFrame({'key': ['K0', 'K1'], 'value': [3, 4]})merged = pd.merge(left, right, on='key', suffixes=('_left', '_right'))
print(merged)
# 输出:
#   key  value_left  value_right
# 0  K0           1            3
# 1  K1           2            4

用途:比较同一指标在不同时间/来源的数据。

建议:始终显式设置 suffixes,避免默认的 _x, _y 造成混淆。


2. 基于多列合并(复合键合并)

有时需要多个字段共同作为“主键”来合并。

pd.merge(df1, df2, on=['date', 'city', 'product_id'], how='inner')

典型场景

  • 按“日期+地区”合并天气与销售数据
  • 按“用户ID+商品ID”合并评分与评论

注意:确保多列组合后能唯一标识一条记录,否则可能产生笛卡尔积(行数暴增)。


3. 使用索引进行合并(left_index / right_index)

当数据以索引为唯一标识时(如时间序列、ID),可以直接用索引合并。

# 基于索引合并
result = pd.merge(df1, df2, left_index=True, right_index=True, how='outer')# 等价于:
result = df1.join(df2, how='outer')

优势:避免创建冗余的 ID 列;适合时间对齐。

示例:对齐不同频率的股票数据(日频 + 周频)


4. concat 的 join 参数:inner vs outer

pd.concat(..., axis=1) 默认是 outer(外连接),但可通过 join='inner' 只保留共有的行。

# 只保留所有表都存在的行
pd.concat([df1, df2, df3], axis=1, join='inner')# 保留所有行(默认)
pd.concat([df1, df2, df3], axis=1, join='outer')

用途

  • join='inner':严格对齐,避免 NaN
  • join='outer':保留全部信息,后续填充缺失值

5. 合并性能优化建议

场景建议
大数据集合并确保连接键是 categoryint 类型(比 object 快)
多次合并先合并小表,再与大表连接
时间序列拼接使用 pd.concat() + ignore_index=False 保持时间索引
内存不足考虑使用 daskpolars 替代

小技巧:合并前检查数据类型:

print(df1['key'].dtype)
print(df2['key'].dtype)
# 确保类型一致,否则可能导致匹配失败!

6. 合并后的质量检查清单(QA)

每次合并后建议检查以下几点:

def check_merge_result(left, right, merged, how):print(f"左表行数: {len(left)}")print(f"右表行数: {len(right)}")print(f"合并后行数: {len(merged)}")if how == 'inner':assert len(merged) <= min(len(left), len(right))elif how == 'left':assert len(merged) >= len(left)elif how == 'right':assert len(merged) >= len(right)elif how == 'outer':assert len(merged) >= max(len(left), len(right))print(f"新增 NaN 数量: {merged.isna().sum().sum()}")

关键问题

  • 行数是否合理?
  • 是否出现大量 NaN?是否预期?
  • 索引是否重复或混乱?
  • 数据类型是否被意外转换?

缺失值处理

为什么会出现缺失值?

在数据整合过程中,以下操作极易引入 NaN

  • pd.concat(..., axis=1) 拼接列时,行索引不完全对齐
  • pd.merge(..., how='left') 左连接时,右表无匹配记录
  • join 扩展属性时,某些 ID 没有对应信息
  • 不同来源数据字段覆盖不全

Pandas 使用 NaN(Not a Number)表示浮点型缺失值,None 表示对象型缺失值,两者在大部分操作中被视为等价。


一、识别缺失值

1. 检查缺失情况

# 查看每个字段缺失数量
df.isnull().sum()# 查看整体缺失比例
df.isnull().mean() * 100# 查看是否有任意缺失
df.isnull().any().any()# 可视化缺失模式(需 seaborn)
import seaborn as sns
sns.heatmap(df.isnull(), cbar=True, yticklabels=False, cmap='viridis')

建议:在每次合并后立即检查缺失情况


二、缺失值的产生场景与应对策略

整合操作缺失原因建议处理方式
concat(axis=0)不同文件字段不一致统一列名 / 补充默认值
concat(axis=1)行索引不对齐对齐索引 / 使用 join='inner'
merge(how='left')右表无匹配键检查数据完整性 / 改用 outer
join()某些 ID 无扩展信息补充默认属性 / 标记为“未知”

三、处理缺失值的常用方法

1. 删除缺失值(dropna

适用于:缺失严重且无法填补,或样本足够多。

# 删除任意含缺失的行
df.dropna(axis=0, how='any')# 删除所有值都缺失的列
df.dropna(axis=1, how='all')# 只在关键列缺失时删除
df.dropna(subset=['user_id', 'order_date'])

风险:可能导致样本偏差或信息丢失。


2. 填充缺失值(fillna

(1)填充固定值
df['category'] = df['category'].fillna('Unknown')
df['price'] = df['price'].fillna(0)
(2)前向/后向填充(适合时间序列)
df['value'] = df['value'].fillna(method='ffill')  # 用前一个值填充
df['value'] = df['value'].fillna(method='bfill')  # 用后一个值填充

method 参数已弃用,推荐使用 ffill / bfill 方法:

df['value'] = df['value'].ffill()
(3)用统计量填充
# 数值型:均值、中位数
df['age'] = df['age'].fillna(df['age'].mean())
df['income'] = df['income'].fillna(df['income'].median())# 分类型:众数
mode_value = df['gender'].mode()[0]  # 取第一个众数
df['gender'] = df['gender'].fillna(mode_value)
(4)用模型预测填充(高级)
from sklearn.impute import KNNImputer
imputer = KNNImputer(n_neighbors=5)
df[['age', 'income']] = imputer.fit_transform(df[['age', 'income']])

3. 插值法填充(interpolate

适用于:时间序列或有序数据。

# 线性插值
df['value'] = df['value'].interpolate(method='linear')# 时间序列插值(考虑时间间隔)
df['value'] = df.set_index('date')['value'].interpolate(method='time').values# 多项式插值(更平滑)
df['value'] = df['value'].interpolate(method='polynomial', order=2)

4. 标记缺失(创建指示变量)

有时“是否缺失”本身就是一个重要特征。

# 创建缺失标志列
df['age_missing'] = df['age'].isnull().astype(int)
df['price_missing'] = df['price'].isnull().astype(int)

用途:在机器学习中作为额外特征,帮助模型理解数据质量。


四、结合数据整合的完整流程示例

# 示例:合并用户信息与订单数据
users = pd.read_csv('users.csv')   # 包含 user_id, age, city
orders = pd.read_csv('orders.csv') # 包含 order_id, user_id, amount# 步骤1:合并
merged = pd.merge(orders, users, on='user_id', how='left')# 步骤2:检查缺失
print("合并后缺失情况:")
print(merged.isnull().sum())# 步骤3:处理缺失
merged['city'] = merged['city'].fillna('Unknown')
merged['age'] = merged['age'].fillna(merged['age'].median())# 步骤4:标记缺失(可选)
merged['age_was_missing'] = (merged['age'] == merged['age'].median()).astype(int)# 步骤5:验证
assert merged.isnull().sum().sum() == 0  # 确保无缺失

五、缺失值处理策略选择指南

场景推荐方法
缺失率 < 5%可考虑删除行
数值型变量均值/中位数填充,或插值
分类型变量众数填充,或新增“Unknown”类别
时间序列前向填充、时间插值
关键字段无匹配检查数据源,避免错误合并
机器学习建模结合 fillna + 缺失标志列

六、最佳实践建议

黄金法则

“宁可标记,也不要随意删除或填充。”

推荐流程

  1. 合并前:统一字段、数据类型、索引
  2. 合并后:立即检查缺失分布
  3. 分析缺失机制
    • MCAR(完全随机缺失)
    • MAR(随机缺失)
    • MNAR(非随机缺失)
  4. 选择合适策略:根据业务逻辑决定如何处理
  5. 记录处理过程:便于复现和审计

七、缺失值处理速查表

检查

  • df.isnull().sum() → 查看各列缺失数
  • df.isnull().mean() → 查看缺失比例

删除

  • df.dropna() → 删除含缺失的行
  • df.dropna(subset=['col']) → 指定列删除

填充

  • df['col'].fillna(0) → 填固定值
  • df['col'].fillna(df['col'].mean()) → 填均值
  • df['col'].ffill() → 前向填充
  • df['col'].interpolate() → 插值

标记

  • df['col_missing'] = df['col'].isnull().astype(int)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/96120.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/96120.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/96120.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c#联合halcon的基础教程(案例:亮度计算、角度计算和缺陷检测)(含halcon代码)

目录 1.环境配置 2.案例一&#xff1a;亮度计算 halcon代码&#xff1a; 主界面代码&#xff1a; 3.案例二&#xff1a; 角度计算 halcon代码&#xff1a; 主界面代码&#xff1a; 4.案例三&#xff1a;缺陷检测 halcon代码&#xff1a; 主界面代码&#xff1a; 通过…

大数据云原生是什么

"云原生"&#xff08;Cloud Native&#xff09;指的是‌利用云计算原生优势&#xff08;弹性、按需服务、自动化、分布式等&#xff09;来设计、构建、部署和运行大数据应用和工作负载的方法论与技术体系‌。它不是简单地“把大数据平台搬到云上”&#xff0c;而是从…

Pytest项目_day16(yaml和parametrize结合)

查询手机号归属地 我们首先可以在YAML文件中定义测试数据 方式一&#xff0c;使用- 注意&#xff1a;当我们需要一次传入两个参数时&#xff0c;需要定义两层迭代&#xff0c;即两层列表不够直观&#xff0c;容易写错 输出的结果为&#xff1a; 然后我们可以将测试数据传入test…

【Nginx指南】从核心原理到生产实践

目录Nginx指南&#xff1a;从核心原理到生产实践引言&#xff1a;Nginx在现代架构中的核心地位一、Nginx核心能力与应用场景1.1 多场景适配的全能型中间件1.2 技术优势&#xff1a;Nginx成为行业标准的关键二、Nginx安装部署&#xff1a;源码编译与包管理方案2.1 源码编译&…

物体检测

目录 1 目标定位 2 地标检测 3 目标检测 4 在卷积网络上实现滑动窗口 5 边界框预测 6 交并比 7 非极大值抑制 8 锚框 9 YOLO算法 10 用u-net进行语义分割 11 转置卷积 12 u-net 结构灵感 1 目标定位 你已经对图片分类有所了解。例如通过这张图片可以识…

es7.x es的高亮与solr高亮查询的对比对比说明

一 solr&es高亮1.1 solr与es高亮功能解释说明&#xff1a;1)高亮配置&#xff1a;fragmentSize(1000) 设置片段长度numOfFragments(1) 指定返回的片段数量preTags() 和 postTags() 设置高亮标记2)字段处理差异&#xff1a;在 ES 中&#xff0c;使用 matchQuery 而非 termQ…

DSP音频算法工程师技能2

一、核心知识准备1. 算法原理3A算法&#xff08;AGC自动增益控制/AEC回声消除/ANS降噪&#xff09;&#xff1a;掌握AEC的NLMS/双讲检测原理&#xff0c;ANS的谱减法/维纳滤波&#xff0c;AGC的压缩曲线设计。熟悉Speex/WebRTC等开源实现。EQ音效&#xff1a;IIR/FIR滤波器设计…

第4章-04-用WebDriver页面元素操作

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年CSDN全站百大博主。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 🏆本文已收录于专栏:Web爬虫入门与实战精讲,后续完整更新内容如下。 文章…

【计算机视觉与深度学习实战】04基于K-Means聚类的图像分割系统设计与实现

摘要 图像分割作为计算机视觉领域的基础任务,在目标检测、医学影像分析、自动驾驶等众多应用中发挥着关键作用。本文基于K-Means聚类算法设计并实现了一个完整的图像分割系统,该系统集成了多种颜色空间转换、自定义初始化策略、空间特征融合等先进技术。通过Python和Tkinter…

Android Studio常用知识总结

一、运行方式1.运行 (Run)当您选择“运行”时&#xff0c;Android Studio 会编译您的应用并将其安装到目标设备或模拟器上。这通常用于&#xff1a;快速部署: 您只想看看应用是否能正常启动并运行&#xff0c;或者进行一些基础的用户界面测试。性能测试: 在正常运行模式下测试应…

设计模式笔记_行为型_访问者模式

1. 访问者模式介绍访问者模式&#xff08;Visitor Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许你在不改变对象结构的前提下&#xff0c;定义作用于这些对象的新操作。访问者模式将操作的逻辑从对象结构中分离出来&#xff0c;使得你可以在运行时动态地添加新的…

数学建模 14 中心对数比变换

用途&#xff1a;是处理成分数据的核心预处理方法&#xff0c;核心目标是解决成分数据的和为常数100% &#xff0c; 导致的维度冗余&#xff0c;非线性相关问题。使得数据满足传统的统计/建模方法&#xff1b;举例子&#xff1a;食品比例中 面粉(50%),糖(30%),水(20%)原理&…

【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day7

&#x1f525;个人主页&#xff1a;草莓熊Lotso &#x1f3ac;作者简介&#xff1a;C研发方向学习者 &#x1f4d6;个人专栏&#xff1a; 《C语言》 《数据结构与算法》《C语言刷题集》《Leetcode刷题指南》 ⭐️人生格言&#xff1a;生活是默默的坚持&#xff0c;毅力是永久的…

污水处理行业的 “智能革命”:边缘计算网关如何重塑传统运维模式?

污水处理行业的 “智能革命”&#xff1a;边缘计算网关如何重塑传统运维模式&#xff1f;在污水处理这一关乎生态环境与可持续发展的关键领域&#xff0c;蓝蜂网关正凭借其先进技术与强大功能&#xff0c;发挥着无可替代的重要作用。作为工业级物联网解决方案的核心组件&#x…

ASP.NET Core 中的多租户 SaaS 应用程序

介绍随着软件即服务 (SaaS) 持续主导技术领域&#xff0c;构建能够高效地从单一代码库服务于多位客户&#xff08;租户&#xff09;的应用程序变得至关重要。ASP.NET Core 凭借其模块化和可扩展的架构&#xff0c;是实现多租户 SaaS 应用程序的强大框架。本文将指导您了解构建多…

JUC之CompletableFuture【中】

文章目录四、CompletableFuture基本使用4.1 默认线程池、无返回值4.2 默认线程池、有返回值4.3 自定义线程池、有返回值4.4 CompletableFuture 获取结果五、对结果进行处理5.1 方法说明5.2 示例5.3 thenApply vs thenApplyAsync5.3.1 核心区别: 执行线程不同5.3.2 thenApply: 同…

环境变量不生效?

目录 添加环境变量 解决不生效 不生效场景 解决办法 大家都知道Windows系统对于开发者来说并不友好&#xff0c;尤其是新手&#xff0c;当然这是相比于linux和MacOS相比&#xff0c;因为开发工具、项目脚本等环境配置要为复杂&#xff0c;注意事项也更多一些。而这篇文章将…

小迪安全v2023学习笔记(六十六讲)—— Java安全SQL注入SSTISPELXXE

文章目录前记WEB攻防——第六十六天Java安全&SPEL表达式&SSTI模板注入&XXE&JDBC&MyBatis注入环境搭建Hello-Java-SecJavaSecJava安全 - SQL注入-JDBC&MyBatisJDBC注入原理语句拼接预编译的错误使用JdbcTemplate正则过滤MyBatis注入原理Like注入Order B…

把 AI 变成「图书馆管理员」——基于检索增强的离线图书语音导航小盒子

标签&#xff1a;检索增强、语音导航、离线 LLM、RAG、ESP32-S3、低功耗、TTS、BLE ---- 1. 背景&#xff1a;读者找不到书的痛苦 高校图书馆每天 5000 人次&#xff0c;高频问题&#xff1a; • “《深度学习》在哪个书架&#xff1f;” • “有没有类似《三体》的科幻&…

架构思维:在AI时代为产品“减负”的终极武器——用结构化智慧破解数字化复杂困局

摘要 数字化产品的复杂度飙升已成为企业发展的核心瓶颈。本文基于架构思维的本质&#xff08;元素、连接、演进&#xff09;&#xff0c;结合5A架构体系&#xff08;业务/信息/应用/技术/治理架构&#xff09;&#xff0c;系统阐述如何通过分而治之、共性沉淀、AI赋能三大策略降…