本文概述
- 连接数据帧
- Works数据帧
- 加入数据帧
- 时间序列友好合并
- 总结
连接和合并DataFrame是从数据分析和机器学习任务开始的核心过程。它是每个数据分析师或数据科学家都应掌握的工具箱之一, 因为在几乎所有情况下, 数据都来自多个源和文件。你可能需要通过某种联接逻辑将所有数据放在一个位置, 然后开始分析。使用诸如查询语言之类的SQL的人可能知道此任务的重要性。即使你要在某些数据上构建一些机器学习模型, 也可能需要将多个csv文件合并到一个DataFrame中。
值得庆幸的是, 你拥有python中最受欢迎的库, 熊猫来助你一臂之力! pandas提供了各种功能, 可以在连接/合并类型操作的情况下轻松地将Series, DataFrame和Panel对象与各种用于索引和关系代数功能的设置逻辑组合在一起。
在本教程中, 你将练习一些标准技术。更具体地说, 你将学习:
- 沿行和列连接DataFrame。
- 通过不同的联接逻辑(例如左联接, 内联接等)在特定键上合并DataFrame。
- 熊猫提供的时间序列友好合并
连接数据帧首先导入将在整个教程中使用的库:pandas
import pandas as pd
你将在要创建的虚拟DataFrame上执行本教程中的所有操作。要创建一个DataFrame, 你可以使用python字典, 例如:
dummy_data1 = {
'id': ['1', '2', '3', '4', '5'], 'Feature1': ['A', 'C', 'E', 'G', 'I'], 'Feature2': ['B', 'D', 'F', 'H', 'J']}
在这里, dummy_data1词典的关键字是列名, 列表中的值是与每个观察值或行对应的数据。要将其转换为pandas DataFrame, 你将使用pandas的DataFrame()函数以及其column参数来命名你的列:
df1 = pd.DataFrame(dummy_data1, columns = ['id', 'Feature1', 'Feature2'])df1
id | 功能1 | 功能2 | |
---|---|---|---|
0 | 1 | 一个 | 乙 |
1 | 2 | C | d |
2 | 3 | 和 | F |
3 | 4 | G | H |
4 | 5 | 一世 | ? |
dummy_data2 = {
'id': ['1', '2', '6', '7', '8'], 'Feature1': ['K', 'M', 'O', 'Q', 'S'], 'Feature2': ['L', 'N', 'P', 'R', 'T']}
df2 = pd.DataFrame(dummy_data2, columns = ['id', 'Feature1', 'Feature2'])df2
id | 功能1 | 功能2 | |
---|---|---|---|
0 | 1 | 该 | 该 |
1 | 2 | 中号 | ? |
2 | 6 | 的 | P |
3 | 7 | 问 | [R |
4 | 8 | 小号 | ? |
dummy_data3 = {
'id': ['1', '2', '3', '4', '5', '7', '8', '9', '10', '11'], 'Feature3': [12, 13, 14, 15, 16, 17, 15, 12, 13, 23]}
df3 = pd.DataFrame(dummy_data3, columns = ['id', 'Feature3'])df3
id | 功能3 | |
---|---|---|
0 | 1 | 12 |
1 | 2 | 13 |
2 | 3 | 14 |
3 | 4 | 15 |
4 | 5 | 16 |
5 | 7 | 17 |
6 | 8 | 15 |
7 | 9 | 12 |
8 | 10 | 13 |
9 | 11 | 23 |
df_row = pd.concat([df1, df2])df_row
id | 功能1 | 功能2 | |
---|---|---|---|
0 | 1 | 一个 | 乙 |
1 | 2 | C | d |
2 | 3 | 和 | F |
3 | 4 | G | H |
4 | 5 | 一世 | ? |
0 | 1 | 该 | 该 |
1 | 2 | 中号 | ? |
2 | 6 | 的 | P |
3 | 7 | 问 | [R |
4 | 8 | 小号 | ? |
df_row_reindex = pd.concat([df1, df2], ignore_index=True)df_row_reindex
id | 功能1 | 功能2 | |
---|---|---|---|
0 | 1 | 一个 | 乙 |
1 | 2 | C | d |
2 | 3 | 和 | F |
3 | 4 | G | H |
4 | 5 | 一世 | ? |
5 | 1 | 该 | 该 |
6 | 2 | 中号 | ? |
7 | 6 | 的 | P |
8 | 7 | 问 | [R |
9 | 8 | 小号 | ? |
pandas还为你提供了一个选项, 可以在串联后为键标记DataFrame, 以便你可以知道哪些数据来自哪个DataFrame。你可以通过传递其他参数键来实现相同目的, 这些参数键在列表中指定DataFrame的标签名称。在这里, 你将分别使用与x和y相同的键对DataFrames df1和df2执行相同的串联操作。
frames = [df1, df2]
df_keys = pd.concat(frames, keys=['x', 'y'])df_keys
id | 功能1 | 功能2 | ||
---|---|---|---|---|
X | 0 | 1 | 一个 | 乙 |
1 | 2 | C | d | |
2 | 3 | 和 | F | |
3 | 4 | G | H | |
4 | 5 | 一世 | ? | |
和 | 0 | 1 | 该 | 该 |
1 | 2 | 中号 | ? | |
2 | 6 | 的 | P | |
3 | 7 | 问 | [R | |
4 | 8 | 小号 | ? |
df_keys.loc['y']
id | 功能1 | 功能2 | |
---|---|---|---|
0 | 1 | 该 | 该 |
1 | 2 | 中号 | ? |
2 | 6 | 的 | P |
3 | 7 | 问 | [R |
4 | 8 | 小号 | ? |
pieces = {'x': df1, 'y': df2}df_piece = pd.concat(pieces)df_piece
id | 功能1 | 功能2 | ||
---|---|---|---|---|
X | 0 | 1 | 一个 | 乙 |
1 | 2 | C | d | |
2 | 3 | 和 | F | |
3 | 4 | G | H | |
4 | 5 | 一世 | ? | |
和 | 0 | 1 | 该 | 该 |
1 | 2 | 中号 | ? | |
2 | 6 | 的 | P | |
3 | 7 | 问 | [R | |
4 | 8 | 小号 | ? |
frames = [ process_your_file(f) for f in files ]
result = pd.concat(frames)
要沿列连接DataFrame, 可以将axis参数指定为1:
df_col = pd.concat([df1, df2], axis=1)df_col
id | 功能1 | 功能2 | id | 功能1 | 功能2 | |
---|---|---|---|---|---|---|
0 | 1 | 一个 | 乙 | 1 | 该 | 该 |
1 | 2 | C | d | 2 | 中号 | ? |
2 | 3 | 和 | F | 6 | 的 | P |
3 | 4 | G | H | 7 | 问 | [R |
4 | 5 | 一世 | ? | 8 | 小号 | ? |
你可以将DataFrames df_row(通过沿行串联df1和df2来创建)和df3联接到公共列(或键)ID上。为此, 请将DataFrames的名称和其他参数作为公共列的名称(此处为id)传递给merge()函数:
df_merge_col = pd.merge(df_row, df3, on='id')df_merge_col
id | 功能1 | 功能2 | 功能3 | |
---|---|---|---|---|
0 | 1 | 一个 | 乙 | 12 |
1 | 1 | 该 | 该 | 12 |
2 | 2 | C | d | 13 |
3 | 2 | 中号 | ? | 13 |
4 | 3 | 和 | F | 14 |
5 | 4 | G | H | 15 |
6 | 5 | 一世 | ? | 16 |
7 | 7 | 问 | [R | 17 |
8 | 8 | 小号 | ? | 15 |
可能要在其上合并DataFrame的列具有不同的名称(在这种情况下不一样)。对于此类合并, 你将必须将参数left_on指定为左侧DataFrame名称, 将right_on指定为右侧DataFrame名称, 例如:
df_merge_difkey = pd.merge(df_row, df3, left_on='id', right_on='id')df_merge_difkey
id | 功能1 | 功能2 | 功能3 | |
---|---|---|---|---|
0 | 1 | 一个 | 乙 | 12 |
1 | 1 | 该 | 该 | 12 |
2 | 2 | C | d | 13 |
3 | 2 | 中号 | ? | 13 |
4 | 3 | 和 | F | 14 |
5 | 4 | G | H | 15 |
6 | 5 | 一世 | ? | 16 |
7 | 7 | 问 | [R | 17 |
8 | 8 | 小号 | ? | 15 |
add_row = pd.Series(['10', 'X1', 'X2', 'X3'], index=['id', 'Feature1', 'Feature2', 'Feature3'])df_add_row = df_merge_col.append(add_row, ignore_index=True)df_add_row
id | 功能1 | 功能2 | 功能3 | |
---|---|---|---|---|
0 | 1 | 一个 | 乙 | 12 |
1 | 1 | 该 | 该 | 12 |
2 | 2 | C | d | 13 |
3 | 2 | 中号 | ? | 13 |
4 | 3 | 和 | F | 14 |
5 | 4 | G | H | 15 |
6 | 5 | 一世 | ? | 16 |
7 | 7 | 问 | [R | 17 |
8 | 8 | 小号 | ? | 15 |
9 | 10 | X1 | X2 | X3 |
完全外部加入
FULL OUTER JOIN合并左右外部联接的结果。联接的DataFrame将包含两个DataFrame的所有记录, 并填写NaN以弥补任一侧缺少的匹配项。你可以通过在merge()函数中将how参数指定为external来执行完全外部联接:
df_outer = pd.merge(df1, df2, on='id', how='outer')df_outer
id | Feature1_x | Feature2_x | Feature1_y | Feature2_y | |
---|---|---|---|---|---|
0 | 1 | 一个 | 乙 | 该 | 该 |
1 | 2 | C | d | 中号 | ? |
2 | 3 | 和 | F | NaN | NaN |
3 | 4 | G | H | NaN | NaN |
4 | 5 | 一世 | ? | NaN | NaN |
5 | 6 | NaN | NaN | 的 | P |
6 | 7 | NaN | NaN | 问 | [R |
7 | 8 | NaN | NaN | 小号 | ? |
df_suffix = pd.merge(df1, df2, left_on='id', right_on='id', how='outer', suffixes=('_left', '_right'))df_suffix
id | Feature1_left | Feature2_left | Feature1_right | Feature2_right | |
---|---|---|---|---|---|
0 | 1 | 一个 | 乙 | 该 | 该 |
1 | 2 | C | d | 中号 | ? |
2 | 3 | 和 | F | NaN | NaN |
3 | 4 | G | H | NaN | NaN |
4 | 5 | 一世 | ? | NaN | NaN |
5 | 6 | NaN | NaN | 的 | P |
6 | 7 | NaN | NaN | 问 | [R |
7 | 8 | NaN | NaN | 小号 | ? |
INNER JOIN仅生成在DataFrame A和DataFrame B中都匹配的记录集。你必须在merge()函数的how参数中传递inner来进行内部联接:
df_inner = pd.merge(df1, df2, on='id', how='inner')df_inner
id | Feature1_x | Feature2_x | Feature1_y | Feature2_y | |
---|---|---|---|---|---|
0 | 1 | 一个 | 乙 | 该 | 该 |
1 | 2 | C | d | 中号 | ? |
RIGHT JOIN会从DataFrame B(右DataFrame)生成完整的记录集, 并在DataFrame A(左DataFrame)中生成匹配的记录(如果有)。如果没有匹配项, 则右侧将包含null。你必须直接在merge()函数的how参数中进行正确的连接:
df_right = pd.merge(df1, df2, on='id', how='right')df_right
id | Feature1_x | Feature2_x | Feature1_y | Feature2_y | |
---|---|---|---|---|---|
0 | 1 | 一个 | 乙 | 该 | 该 |
1 | 2 | C | d | 中号 | ? |
2 | 6 | NaN | NaN | 的 | P |
3 | 7 | NaN | NaN | 问 | [R |
4 | 8 | NaN | NaN | 小号 | ? |
LEFT JOIN会从DataFrame A(左侧DataFrame)生成完整的记录集, 并在DataFrame B(右侧DataFrame)中生成匹配的记录(如果有)。如果没有匹配项, 则左侧将包含null。你必须在merge()函数的how参数中向左传递以进行左连接:
df_left = pd.merge(df1, df2, on='id', how='left')df_left
id | Feature1_x | Feature2_x | Feature1_y | Feature2_y | |
---|---|---|---|---|---|
0 | 1 | 一个 | 乙 | 该 | 该 |
1 | 2 | C | d | 中号 | ? |
2 | 3 | 和 | F | NaN | NaN |
3 | 4 | G | H | NaN | NaN |
4 | 5 | 一世 | ? | NaN | NaN |
有时你可能必须对索引或行标签执行联接。为此, 你必须将right_index(用于右侧DataFrame的索引)和left_index(用于左侧DataFrame的索引)指定为True:
df_index = pd.merge(df1, df2, right_index=True, left_index=True)df_index
id_x | Feature1_x | Feature2_x | id_y | Feature1_y | Feature2_y | |
---|---|---|---|---|---|---|
0 | 1 | 一个 | 乙 | 1 | 该 | 该 |
1 | 2 | C | d | 2 | 中号 | ? |
2 | 3 | 和 | F | 6 | 的 | P |
3 | 4 | G | H | 7 | 问 | [R |
4 | 5 | 一世 | ? | 8 | 小号 | ? |
可选地, asof合并可以执行逐组合并。除on键上最接近的匹配项外, 此键均等地匹配by键。
例如, 你可能有交易和报价, 并且想要将它们合并。在这里, 左边的DataFrame被选作交易, 右边的DataFrame被选为报价。它们在关键时间开始合并, 并通过股票代码进行分组合并。
trades = pd.DataFrame({
'time': pd.to_datetime(['20160525 13:30:00.023', '20160525 13:30:00.038', '20160525 13:30:00.048', '20160525 13:30:00.048', '20160525 13:30:00.048']), 'ticker': ['MSFT', 'MSFT', 'GOOG', 'GOOG', 'AAPL'], 'price': [51.95, 51.95, 720.77, 720.92, 98.00], 'quantity': [75, 155, 100, 100, 100]}, columns=['time', 'ticker', 'price', 'quantity'])quotes = pd.DataFrame({
'time': pd.to_datetime(['20160525 13:30:00.023', '20160525 13:30:00.023', '20160525 13:30:00.030', '20160525 13:30:00.041', '20160525 13:30:00.048', '20160525 13:30:00.049', '20160525 13:30:00.072', '20160525 13:30:00.075']), 'ticker': ['GOOG', 'MSFT', 'MSFT', 'MSFT', 'GOOG', 'AAPL', 'GOOG', 'MSFT'], 'bid': [720.50, 51.95, 51.97, 51.99, 720.50, 97.99, 720.50, 52.01], 'ask': [720.93, 51.96, 51.98, 52.00, 720.93, 98.01, 720.88, 52.03]}, columns=['time', 'ticker', 'bid', 'ask'])
trades
时间 | 股票代码 | 价钱 | 数量 | |
---|---|---|---|---|
0 | 2016-05-25 13:30:00.023 | 微软 | 51.95 | 75 |
1 | 2016-05-25 13:30:00.038 | 微软 | 51.95 | 155 |
2 | 2016-05-25 13:30:00.048 | 高格 | 720.77 | 100 |
3 | 2016-05-25 13:30:00.048 | 高格 | 720.92 | 100 |
4 | 2016-05-25 13:30:00.048 | AAPL | 98.00 | 100 |
quotes
时间 | 股票代码 | 出价 | 问 | |
---|---|---|---|---|
0 | 2016-05-25 13:30:00.023 | 高格 | 720.50 | 720.93 |
1 | 2016-05-25 13:30:00.023 | 微软 | 51.95 | 51.96 |
2 | 2016-05-25 13:30:00.030 | 微软 | 51.97 | 51.98 |
3 | 2016-05-25 13:30:00.041 | 微软 | 51.99 | 52.00 |
4 | 2016-05-25 13:30:00.048 | 高格 | 720.50 | 720.93 |
5 | 2016-05-25 13:30:00.049 | AAPL | 97.99 | 98.01 |
6 | 2016-05-25 13:30:00.072 | 高格 | 720.50 | 720.88 |
7 | 2016-05-25 13:30:00.075 | 微软 | 52.01 | 52.03 |
df_merge_asof = pd.merge_asof(trades, quotes, on='time', by='ticker')df_merge_asof
时间 | 股票代码 | 价钱 | 数量 | 出价 | 问 | |
---|---|---|---|---|---|---|
0 | 2016-05-25 13:30:00.023 | 微软 | 51.95 | 75 | 51.95 | 51.96 |
1 | 2016-05-25 13:30:00.038 | 微软 | 51.95 | 155 | 51.97 | 51.98 |
2 | 2016-05-25 13:30:00.048 | 高格 | 720.77 | 100 | 720.50 | 720.93 |
3 | 2016-05-25 13:30:00.048 | 高格 | 720.92 | 100 | 720.50 | 720.93 |
4 | 2016-05-25 13:30:00.048 | AAPL | 98.00 | 100 | NaN | NaN |
【在Pandas中加入DataFrames】你还可以为时间列设置预定义的公差级别。假设你只希望在报价时间和交易时间之间的2ms之内进行asof合并, 那么你将必须指定公差参数:
df_merge_asof_tolerance = pd.merge_asof(trades, quotes, on='time', by='ticker', tolerance=pd.Timedelta('2ms'))df_merge_asof_tolerance
时间 | 股票代码 | 价钱 | 数量 | 出价 | 问 | |
---|---|---|---|---|---|---|
0 | 2016-05-25 13:30:00.023 | 微软 | 51.95 | 75 | 51.95 | 51.96 |
1 | 2016-05-25 13:30:00.038 | 微软 | 51.95 | 155 | NaN | NaN |
2 | 2016-05-25 13:30:00.048 | 高格 | 720.77 | 100 | 720.50 | 720.93 |
3 | 2016-05-25 13:30:00.048 | 高格 | 720.92 | 100 | 720.50 | 720.93 |
4 | 2016-05-25 13:30:00.048 | AAPL | 98.00 | 100 | NaN | NaN |
总结欢呼!你到了本教程的结尾。在本教程中, 你学习了使用pandas库的concat()和merge()函数基于几种逻辑来串联和合并DataFrame。最后, 你还练习了特殊功能merge_asof()来合并时间序列DataFrame。在此过程中, 你还学会了如何使用DataFrames的索引。你还可以探索其他几种选择, 以在熊猫中加入DataFrames, 我鼓励你查看其出色的文档。探索愉快!
本教程使用以下资源来帮助编写它:
- https://pandas.pydata.org/pandas-docs/stable/merging.html
推荐阅读
- Python中的文档字符串
- R Rstudio使用debugr进行调试
- 自动化机器学习(Python的TPOT库)
- 用Python揭开关键统计的神秘面纱
- R中的for循环用法
- 在R中创建列表
- 关于扑克牌的一些讨论——《Fluent Python 2》读书笔记
- web.xml servletservlet-mapping配置
- Android开发-在Android应用里实现自动发送邮件的功能