
7 个高效数据合并的 Pandas 技巧
图片由 Editor | ChatGPT 提供
引言
数据合并是将来自不同来源的数据组合成一个统一数据集的过程。在许多数据科学工作流中,相关信息分散在多个表或文件中——例如,银行客户资料和他们的交易历史——为了解锁更深层次的洞见并促进有影响力的分析,数据合并变得至关重要。然而,由于不一致性、异构数据格式,或仅仅是因为所涉及数据集的庞大规模,高效执行数据合并过程可能非常艰巨。
本文揭示了七个实用的Pandas技巧,以加速您的数据合并过程,让您能够更专注于数据科学和机器学习工作流的其他关键阶段。不用说,由于Pandas库在下面的代码示例中扮演着主角,请确保您首先执行“import pandas as pd
”!
1. 使用 merge() 进行安全的一对一连接
使用Pandas的merge()
函数合并两个具有共同键属性或标识符的数据集时,可以通过设置validate='one_to_one'
参数来使其高效且稳健。这能确保合并键在两个数据帧中都具有唯一值,并捕获可能的重复错误,防止它们传播到后续的数据分析阶段。
1 2 3 4 |
left = pd.DataFrame({'id':[1,2,3], 'name':['Ana','Bo','Cy']}) right = pd.DataFrame({'id':[1,2,3], 'spent':[10,20,30]}) merged = pd.merge(left, right, on='id', how='left', validate='one_to_one') |
我们的示例即时创建了两个小型数据帧,但您可以用自己的“left”和“right”数据帧来尝试,只要它们有一个共同的合并键(在我们的示例中是'id'
列)。
渴望练习吗?尝试在how参数中使用不同的连接方式,如right、outer或inner连接,也尝试替换任一数据帧中的id
值3,看看它如何影响合并结果。我也鼓励您在接下来的四个示例中进行类似的实验。
2. 使用 DataFrame.join() 进行基于索引的连接
将跨数据帧的共同合并键转换成索引有助于加快合并速度,尤其是在涉及多次连接时。以下示例在将合并键设置为索引后,使用其中一个数据帧的join()
方法与另一个数据帧合并。同样,可以考虑不同的连接方式。
1 2 3 4 |
users = pd.DataFrame({'user_id':[101,102,103], 'name':['Ada','Ben','Cal']}).set_index('user_id') scores = pd.DataFrame({'user_id':[101,103], 'score':[88,91]}).set_index('user_id') joined = users.join(scores, how='left') |
3. 使用 merge_asof() 进行时间感知连接
在高粒度的时间序列数据中,例如购物订单及其相关的报价单,精确的时间戳可能并不总能匹配。因此,与其在合并键(即时间)上寻求精确匹配,不如采用最近键匹配的方法。这可以通过merge_asof()
函数高效完成,如下所示:
1 2 3 4 |
tickets = pd.DataFrame({'t':[1,3,7], 'price':[100,102,101]}) orders = pd.DataFrame({'t':[2,4,6], 'qty':[5,2,8]}) asof_merged = pd.merge_asof(orders.sort_values('t'), tickets.sort_values('t'), on='t', direction='backward') |
4. 使用 Series.map() 进行快速查找
当您需要从查找表(如一个将产品ID映射到名称的Pandas Series
)中添加单个列时,map()
方法是比完整连接更快、更简洁的替代方案。方法如下:
1 2 3 4 |
orders = pd.DataFrame({'product_id':[2001,2002,2001,2003]}) product_lookup = pd.Series({2001:'Laptop', 2002:'Headphones', 2003:'Monitor'}) orders['product_name'] = orders['product_id'].map(product_lookup) |
5. 使用 drop_duplicates() 防止意外合并
如果我们忽略了可能重复的键(有时是无意的),而这些键最终本不应该存在,那么经常会发生意想不到的多对多合并。在合并前仔细分析数据并确保删除可能的重复项,可以防止在处理大型数据集时出现行数爆炸和内存飙升。
1 2 3 4 5 |
orders = pd.DataFrame({'id':[1,1,2], 'item':['apple','banana','cherry']}) customers = pd.DataFrame({'id':[1,2,2], 'name':['Alice','Bob','Bob-dupli']}) customers = customers.drop_duplicates(subset='id') merged = pd.merge(orders, customers, on='id', how='left', validate='many_to_one') |
6. 使用 CategoricalDtype 进行快速键匹配
另一种减少内存飙升并加速合并过程中比较速度的方法是,使用CategoricalDtype
对象将合并键转换为分类变量。如果您的数据集的键由长而重复的字符串组成,例如字母数字客户代码,在合并前应用此技巧,您会真正感受到差异。
1 2 3 4 5 6 7 8 |
left = pd.DataFrame({'k':['a','b','c','a']}) right = pd.DataFrame({'k':['a','b'], 'v':[1,2]}) cat = pd.api.types.CategoricalDtype(categories=right['k'].unique()) left['k'] = left['k'].astype(cat) right['k'] = right['k'].astype(cat) merged = pd.merge(left, right, on='k', how='left') |
7. 使用 loc[] 投影精简连接负载
相信我,这比听起来简单得多。这个技巧特别适用于包含大量特征的数据集,它包括在合并前仅选择必要的列。通过在过程中简单地添加几个列级别的loc[]
投影,减少数据重排、比较和内存存储可以带来真正的改变。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
sales = pd.DataFrame({ 'order_id':[101,102,103], 'customer_id':[1,2,3], 'amount':[250,120,320], 'discount_code':['SPRING','NONE','NONE'] }) customers = pd.DataFrame({ 'customer_id':[1,2,3], 'region':['EU','US','APAC'], 'notes':['VIP','Late payer','New customer'] }) customers_selected = customers.loc[:, ['customer_id','region']] sales_selected = sales.loc[:, ['order_id','customer_id','amount']] merged = pd.merge(sales_selected, customers_selected, on='customer_id', how='left') |
总结
通过将本文中的七个Pandas技巧应用于大型数据集,您可以显著提高数据合并过程的效率。以下是我们所学内容的快速回顾。
技巧 | 价值 |
---|---|
pd.merge() |
一对一键验证,防止多对多爆炸浪费时间和内存。 |
DataFrame.join() |
直接基于索引的连接减少了键对齐的开销,并简化了多重连接链。 |
pd.merge_asof() |
在时间序列数据上进行排序后的最近键连接,无需繁琐的重采样。 |
Series.map() |
基于查找的键值丰富比完整的DataFrame连接更快。 |
DataFrame.drop_duplicates() |
删除重复键可防止多对多爆炸和不必要的处理。 |
CategoricalDtype |
将复杂的字符串键转换为分类类型可节省内存并加快相等性比较。 |
DataFrame.loc[] |
在合并前仅选择需要的列。 |
暂无评论。