pandas提供了各种工具,可以在连接/合并类型操作的情况下,轻松地将Series,DataFrame和Panel对象与索引和关系代数功能的各种设置逻辑组合在一起。
目录
连接对象
在其他轴上设置逻辑
连接使用append
忽略连接轴上的索引
与混合ndims连接
更多与组密钥连接
行追加到数据帧
数据库风格的DataFrame加入/合并
关于合并方法(关系代数)的简要介绍
检查重复键
合并指标
合并Dtypes
加入索引
连接索引上的键列
将单个索引连接到多索引
加入两个多索引
合并列和索引级别的组合
重叠值列
连接多个DataFrame或Panel对象
将Series或DataFrame列中的值合并在一起
时间序列友好合并
合并有序数据
合并ASOF
该concat()
函数(在主pandas命名空间中)执行沿轴执行连接操作的所有繁重工作,同时在其他轴上执行索引(如果有)的可选集合逻辑(并集或交集)。请注意,我说“if any”因为Series只有一个可能的串联轴。
在深入了解所有细节及其功能之前concat
,这里有一个简单的例子:
df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']},
index=[0, 1, 2, 3])
df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'],
'B': ['B4', 'B5', 'B6', 'B7'],
'C': ['C4', 'C5', 'C6', 'C7'],
'D': ['D4', 'D5', 'D6', 'D7']},
index=[4, 5, 6, 7])
df3 = pd.DataFrame({'A': ['A8', 'A9', 'A10', 'A11'],
'B': ['B8', 'B9', 'B10', 'B11'],
'C': ['C8', 'C9', 'C10', 'C11'],
'D': ['D8', 'D9', 'D10', 'D11']},
index=[8, 9, 10, 11])
frames = [df1, df2, df3]
result = pd.concat(frames)
像ndarrays其兄弟功能numpy.concatenate
,pandas.concat
采用均匀类型对象的列表或字典,并以“做什么与其他轴”的一些配置的处理连接它们:
pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False,
keys=None, levels=None, names=None, verify_integrity=False,
copy=True)
objs
:Series,DataFrame或Panel对象的序列或映射。如果传递了dict,则排序的键将用作keys参数,除非它被传递,在这种情况下将选择值(见下文)。任何None对象都将以静默方式删除,除非它们都是None,在这种情况下将引发ValueError。axis
:{0,1,...},默认为0.要连接的轴。join
:{'inner','outer'},默认为'outer'。如何处理其他轴上的索引。结合的外部和交叉的内部。ignore_index
:boolean,默认为False。如果为True,请不要在连接轴上使用索引值。生成的轴将标记为0,...,n - 1.如果要连接并置轴没有有意义的索引信息的对象,这将非常有用。请注意,在连接中仍然遵循其他轴上的索引值。join_axes
:索引对象列表。用于其他n - 1轴的特定索引,而不是执行内部/外部设置逻辑。keys
:序列,默认无。使用传递的键作为最外层来构造层次索引。如果传递了多个级别,则应包含元组。levels
:序列列表,默认无。用于构造MultiIndex的特定级别(唯一值)。否则,他们将从键中推断出来。names
:list,默认无。生成的分层索引中的级别的名称。verify_integrity
:boolean,默认为False。检查新的连锁轴是否包含重复项。相对于实际数据连接,这可能非常昂贵。copy
:boolean,默认为True。如果为False,则不要不必要地复制数据。没有一点上下文,许多这些论点都没有多大意义。让我们重温上面的例子。假设我们想要将特定键与切碎的DataFrame的每个片段相关联。我们可以使用keys
参数来做到这一点 :
result = pd.concat(frames, keys=['x', 'y', 'z'])
如您所见(如果您已阅读其余文档),结果对象的索引具有分层索引。这意味着我们现在可以按键选择每个块:
result.loc['y']
A B C D
4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
看看它如何非常有用并不是一件容易的事。有关此功能的更多细节如下。
注意:值得注意的是
concat()
(并因此append()
)制作数据的完整副本,并且不断重复使用此功能可能会产生重大的性能损失。如果需要对多个数据集使用该操作,请使用列表推导。
frames = [ process_your_file(f) for f in files ]
result = pd.concat(frames)
将多个DataFrame粘合在一起时,您可以选择如何处理其他轴(除了连接的轴之外)。这可以通过以下三种方式完成:
join='outer'
。这是默认选项,因为它会导致零信息丢失。join='inner'
。join_axes
参数的特定索引。以下是每种方法的示例。首先,默认join='outer'
行为:
df4 = pd.DataFrame({'B': ['B2', 'B3', 'B6', 'B7'],
'D': ['D2', 'D3', 'D6', 'D7'],
'F': ['F2', 'F3', 'F6', 'F7']},
index=[2, 3, 6, 7])
result = pd.concat([df1, df4], axis=1, sort=False)
警告
版本0.23.0已更改。
默认行为
join='outer'
是对另一个轴进行排序(在本例中为列)。在未来版本的pandas中,默认情况下不进行排序。我们现在指定sort=False
选择加入新行为。
这是同样的事情join='inner'
:
result = pd.concat([df1, df4], axis=1, join='inner')
最后,假设我们只想重用原始DataFrame中的确切索引:
result = pd.concat([df1, df4], axis=1, join_axes=[df1.index])
append
一个有用的快捷方式concat()
是append()
实例方法Series
和DataFrame
。这些方法实际上早于此 concat
。它们连接在一起axis=0
,即索引:
result = df1.append(df2)
在这种情况下DataFrame
,索引必须是不相交的,但列不需要是:
result = df1.append(df4)
append
可能需要多个对象连接:
result = df1.append([df2, df3])
注意:与
append()
附加到原始列表并返回的方法不同None
,append()
此处不会修改df1
并返回其df2
附加的副本。
对于DataFrame
没有有意义索引的s,您可能希望附加它们并忽略它们可能具有重叠索引的事实。为此,请使用以下ignore_index
参数:
result = pd.concat([df1, df4], ignore_index=True)
这也是一个有效的论据DataFrame.append()
:
result = df1.append(df4, ignore_index=True)
你可以连接Series
和DataFrame
s 的混合。该 Series
会转化为DataFrame
与列名的名称Series
。
s1 = pd.Series(['X0', 'X1', 'X2', 'X3'], name='X')
result = pd.concat([df1, s1], axis=1)
注意:由于我们将a连接
Series
到aDataFrame
,因此我们可以获得相同的结果DataFrame.assign()
。要连接任意数量的pandas对象(DataFrame
或Series
),请使用concat
。
如果未命名Series
,则将连续编号。
s2 = pd.Series(['_0', '_1', '_2', '_3'])
result = pd.concat([df1, s2, s2, s2], axis=1)
传递ignore_index=True
将删除所有名称引用。
result = pd.concat([df1, s1], axis=1, ignore_index=True)
参数的一个相当常见的用法是在基于现有keys
创建new时覆盖列名。请注意默认行为如何让结果 继承父名称(当存在时)。DataFrame
Series
DataFrame
Series
s3 = pd.Series([0, 1, 2, 3], name='foo')
s4 = pd.Series([0, 1, 2, 3])
s5 = pd.Series([0, 1, 4, 5])
pd.concat([s3, s4, s5], axis=1)
Out[25]:
foo 0 1
0 0 0 0
1 1 1 1
2 2 2 4
3 3 3 5
通过keys
参数,我们可以覆盖现有的列名。
pd.concat([s3, s4, s5], axis=1, keys=['red','blue','yellow'])
Out[26]:
red blue yellow
0 0 0 0
1 1 1 1
2 2 2 4
3 3 3 5
让我们考虑一下第一个例子的变体:
result = pd.concat(frames, keys=['x', 'y', 'z'])
您也可以传递一个dict,concat
在这种情况下,dict键将用于keys
参数(除非指定了其他键):
pieces = {'x': df1, 'y': df2, 'z': df3}
result = pd.concat(pieces)
result = pd.concat(pieces, keys=['z', 'y'])
创建的MultiIndex具有从传递的键和DataFrame
片段的索引构造的级别:
result.index.levels
Out[31]: FrozenList([['z', 'y'], [4, 5, 6, 7, 8, 9, 10, 11]])
如果您希望指定其他级别(有时会出现这种情况),您可以使用以下levels
参数:
result = pd.concat(pieces, keys=['x', 'y', 'z'],
levels=[['z', 'y', 'x', 'w']],
names=['group_key'])
result.index.levels
Out[33]: FrozenList([['z', 'y', 'x', 'w'], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]])
这是相当深奥的,但实际上有必要实现GroupBy这样的事情,其中分类变量的顺序是有意义的。
虽然不是特别有效(因为必须创建一个新对象),你可以DataFrame
通过传递一个Series
或一个dict来 向a追加一行append
,这将返回一个新的DataFrame
,如上所述。
s2 = pd.Series(['X0', 'X1', 'X2', 'X3'], index=['A', 'B', 'C', 'D'])
result = df1.append(s2, ignore_index=True)
您应该使用ignore_index
此方法来指示DataFrame丢弃其索引。如果要保留索引,则应构造适当索引的DataFrame并追加或连接这些对象。
您还可以传递dicts或Series列表:
dicts = [{'A': 1, 'B': 2, 'C': 3, 'X': 4},
{'A': 5, 'B': 6, 'C': 7, 'Y': 8}]
result = df1.append(dicts, ignore_index=True)
pandas具有功能齐全的高性能内存中连接操作,与SQL等关系数据库非常相似。与其他开源实现(如base::merge.data.frame
R中)相比,这些方法的性能明显更好(在某些情况下甚至超过了一个数量级)。原因是仔细的算法设计和数据的内部布局DataFrame
。
有关一些高级策略,请参阅食谱。
熟悉SQL但对pandas不熟悉的用户可能会对与SQL进行比较感兴趣 。
pandas提供单个函数,merge()
作为DataFrame
对象之间所有标准数据库连接操作的入口点:
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
left_index=False, right_index=False, sort=True,
suffixes=('_x', '_y'), copy=True, indicator=False,
validate=None)
left
:一个DataFrame对象。
right
:另一个DataFrame对象。
on
:要加入的列或索引级别名称。必须在左侧和右侧DataFrame对象中找到。如果没有通过,left_index
并且right_index
是False
在DataFrames列的交叉点会被推断为联接键。
left_on
:左侧DataFrame中的列或索引级别用作键。可以是列名,索引级名称,也可以是长度等于DataFrame长度的数组。
right_on
:来自右侧DataFrame的列或索引级别用作键。可以是列名,索引级名称,也可以是长度等于DataFrame长度的数组。
left_index
:If True
,使用左侧DataFrame中的索引(行标签)作为其连接键。对于具有MultiIndex(分层)的DataFrame,级别数必须与右侧DataFrame中的连接键数相匹配。
right_index
:与left_index
右侧DataFrame的用法相同
how
:其一'left'
,'right'
,'outer'
,'inner'
。默认为inner
。有关每种方法的详细说明,请参见下文。
sort
:按字典顺序通过连接键对结果DataFrame进行排序。默认为True
,设置为False
在很多情况下会显着提高性能。
suffixes
:要应用于重叠列的字符串后缀元组。默认为。('_x', '_y')
copy
:始终True
从传递的DataFrame对象复制数据(默认),即使不需要重建索引也是如此。在许多情况下无法避免,但可能会提高性能/内存使用率。可以避免复制的情况在某种程度上是病态的,但仍然提供了这种选择。
indicator
:向输出的DataFrame添加一列,其中_merge
包含有关每行源的信息。_merge
是分类类型,并且left_only
对于其合并键仅出现在'left'
DataFrame 中的观察值,对于其合并键仅出现在DataFrame中right_only
的观察'right'
值,以及both
在两者中都找到观察点的合并键的值,取值。
validate
:string,默认无。如果指定,则检查merge是否为指定类型。
版本0.21.0中的新功能。
注意:用于指定索引水平支撑
on
,left_on
以及right_on
在0.23.0版加入参数。
返回类型将与left
。相同。如果left
是DataFrame
并且right
是DataFrame的子类,则返回类型仍然是 DataFrame
。
merge
是pandas命名空间中的一个函数,它也可以作为 DataFrame
实例方法merge()
使用,调用 DataFrame
被隐式地视为连接中的左对象。
相关join()
方法,merge
内部用于索引索引(默认情况下)和列索引连接。如果您只加入索引,您可能希望使用DataFrame.join
以节省一些打字。
像SQL这样的关系数据库的有经验的用户将熟悉用于描述两个类似SQL表的结构(DataFrame
对象)之间的连接操作的术语。有几种情况需要考虑,了解哪些非常重要:
DataFrame
在索引上连接两个对象时(必须包含唯一值)。DataFrame
。注意:在列上连接列时(可能是多对多连接),将丢弃传递的
DataFrame
对象上的任何索引。
值得花些时间了解多对多 连接案例的结果。在SQL /标准关系代数中,如果两个表中的键组合出现多次,则生成的表将具有关联数据的笛卡尔积。这是一个非常基本的例子,它有一个独特的组合键:
left = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3']})
right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']})
result = pd.merge(left, right, on='key')
这是一个包含多个连接键的更复杂的示例。默认情况下,只有出现在left
和right
存在的键(交叉点) how='inner'
。
left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
'key2': ['K0', 'K1', 'K0', 'K1'],
'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3']})
right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
'key2': ['K0', 'K0', 'K0', 'K0'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']})
result = pd.merge(left, right, on=['key1', 'key2'])
该how
参数merge
指定如何确定要在结果表中包含哪些键。如果组合键没有出现在左表或右表中,则联接表中的值将为NA
。以下是how
选项及其SQL等效名称的摘要:
合并方法 | SQL加入名称 | 描述 |
---|---|---|
left |
LEFT OUTER JOIN |
仅使用左框架中的按键 |
right |
RIGHT OUTER JOIN |
仅使用右框架中的按键 |
outer |
FULL OUTER JOIN |
使用两个帧中的键的并集 |
inner |
INNER JOIN |
使用两个帧的交叉键 |
result = pd.merge(left, right, how='left', on=['key1', 'key2'])
result = pd.merge(left, right, how='right', on=['key1', 'key2'])
result = pd.merge(left, right, how='outer', on=['key1', 'key2'])
result = pd.merge(left, right, how='inner', on=['key1', 'key2'])
以下是DataFrames中重复连接键的另一个示例:
left = pd.DataFrame({'A' : [1,2], 'B' : [2, 2]})
right = pd.DataFrame({'A' : [4,5,6], 'B': [2,2,2]})
result = pd.merge(left, right, on='B', how='outer')
警告:在重复键上加入/合并可能导致返回的帧是行维度的乘法,这可能导致内存溢出。在加入大型DataFrame之前,用户有责任管理密钥中的重复值。
版本0.21.0中的新功能。
用户可以使用该validate
参数自动检查其合并键中是否存在意外重复。在合并操作之前检查密钥唯一性,因此应防止内存溢出。检查密钥唯一性也是确保用户数据结构符合预期的好方法。
在以下示例中,B
右侧 有重复值DataFrame
。由于这不是一对一的合并 - 如参数中所指定的 validate
- 将引发异常。
left = pd.DataFrame({'A' : [1,2], 'B' : [1, 2]})
right = pd.DataFrame({'A' : [4,5,6], 'B': [2, 2, 2]})
result = pd.merge(left, right, on='B', how='outer', validate="one_to_one")
...
MergeError: Merge keys are not unique in right dataset; not a one-to-one merge
如果用户知道右侧的重复项DataFrame
但希望确保左侧DataFrame中没有重复项,则可以使用该validate='one_to_many'
参数,这不会引发异常。
pd.merge(left, right, on='B', how='outer', validate="one_to_many")
Out[53]:
A_x B A_y
0 1 1 NaN
1 2 2 4.0
2 2 2 5.0
3 2 2 6.0
merge()
接受这个论点indicator
。如果True
,将调用的Categorical类型列_merge
添加到具有值的输出对象:
观察起源 _merge
值仅在 'left'
框架中合并密钥left_only
仅在 'right'
框架中合并密钥right_only
合并两个框架中的键 both
df1 = pd.DataFrame({'col1': [0, 1], 'col_left':['a', 'b']})
df2 = pd.DataFrame({'col1': [1, 2, 2],'col_right':[2, 2, 2]})
pd.merge(df1, df2, on='col1', how='outer', indicator=True)
Out[56]:
col1 col_left col_right _merge
0 0 a NaN left_only
1 1 b 2.0 both
2 2 NaN 2.0 right_only
3 2 NaN 2.0 right_only
该indicator
说法也将接受字符串参数,在这种情况下,指数函数将使用所传递的字符串的值作为名称的指标列。
pd.merge(df1, df2, on='col1', how='outer', indicator='indicator_column')
Out[57]:
col1 col_left col_right indicator_column
0 0 a NaN left_only
1 1 b 2.0 both
2 2 NaN 2.0 right_only
3 2 NaN 2.0 right_only
版本0.19.0中的新功能。
合并将保留连接键的dtype。
left = pd.DataFrame({'key': [1], 'v1': [10]})
left
Out[59]:
key v1
0 1 10
right = pd.DataFrame({'key': [1, 2], 'v1': [20, 30]})
right
Out[61]:
key v1
0 1 20
1 2 30
我们可以保留连接键:
pd.merge(left, right, how='outer')
Out[62]:
key v1
0 1 10
1 1 20
2 2 30
pd.merge(left, right, how='outer').dtypes
Out[63]:
key int64
v1 int64
dtype: object
当然,如果您缺少引入的值,则生成的dtype将是upcast。
pd.merge(left, right, how='outer', on='key')
Out[64]:
key v1_x v1_y
0 1 10.0 20
1 2 NaN 30
pd.merge(left, right, how='outer', on='key').dtypes
Out[65]:
key int64
v1_x float64
v1_y int64
dtype: object
版本0.20.0中的新功能。
合并将保留category
mergands的dtypes。另请参阅有关分类的部分。
左框架。
from pandas.api.types import CategoricalDtype
X = pd.Series(np.random.choice(['foo', 'bar'], size=(10,)))
X = X.astype(CategoricalDtype(categories=['foo', 'bar']))
left = pd.DataFrame({'X': X,
'Y': np.random.choice(['one', 'two', 'three'], size=(10,))})
left
Out[70]:
X Y
0 bar one
1 foo one
2 foo three
3 bar three
4 foo one
5 bar one
6 bar three
7 bar three
8 bar three
9 foo three
left.dtypes
Out[71]:
X category
Y object
dtype: object
正确的框架。
right = pd.DataFrame({
'X': pd.Series(['foo', 'bar'],
dtype=CategoricalDtype(['foo', 'bar'])),
'Z': [1, 2]
})
right
Out[73]:
X Z
0 foo 1
1 bar 2
right.dtypes
Out[74]:
X category
Z int64
dtype: object
合并后的结果:
result = pd.merge(left, right, how='outer')
result
Out[76]:
X Y Z
0 bar one 2
1 bar three 2
2 bar one 2
3 bar three 2
4 bar three 2
5 bar three 2
6 foo one 1
7 foo three 1
8 foo one 1
9 foo three 1
result.dtypes
Out[77]:
X category
Y object
Z int64
dtype: object
注意:类别dtypes必须完全相同,即相同的类别和有序属性。否则结果将强制转换为
object
dtype。
注意:与
category
dtype 合并相比,在相同的dtypes上合并可以非常高效object
。
DataFrame.join()
是一种方便的方法,用于将两个可能不同索引的列组合DataFrames
成单个结果 DataFrame
。这是一个非常基本的例子:
left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
'B': ['B0', 'B1', 'B2']},
index=['K0', 'K1', 'K2'])
right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],
'D': ['D0', 'D2', 'D3']},
index=['K0', 'K2', 'K3'])
result = left.join(right)
result = left.join(right, how='outer')
与上面相同,但有how='inner'
。
result = left.join(right, how='inner')
此处的数据对齐位于索引(行标签)上。使用merge
另外的参数指示它使用索引可以实现相同的行为:
result = pd.merge(left, right, left_index=True, right_index=True, how='outer')
result = pd.merge(left, right, left_index=True, right_index=True, how='inner');
join()
获取一个可选on
参数,该参数可以是一列或多列名称,它指定传递的DataFrame
对齐在该列中的列上DataFrame
。这两个函数调用完全等效:
left.join(right, on=key_or_keys)
pd.merge(left, right, left_on=key_or_keys, right_index=True,
how='left', sort=False)
显然,您可以选择更方便的形式。对于多对一连接(其中一个DataFrame
已经通过连接键索引),使用join
可能更方便。这是一个简单的例子:
left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3'],
'key': ['K0', 'K1', 'K0', 'K1']})
right = pd.DataFrame({'C': ['C0', 'C1'],
'D': ['D0', 'D1']},
index=['K0', 'K1'])
result = left.join(right, on='key')
result = pd.merge(left, right, left_on='key', right_index=True,
how='left', sort=False);
要连接多个键,传递的DataFrame必须具有MultiIndex
:
left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3'],
'key1': ['K0', 'K0', 'K1', 'K2'],
'key2': ['K0', 'K1', 'K0', 'K1']})
index = pd.MultiIndex.from_tuples([('K0', 'K0'), ('K1', 'K0'),
('K2', 'K0'), ('K2', 'K1')])
right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']},
index=index)
现在可以通过传递两个键列名来加入:
result = left.join(right, on=['key1', 'key2'])
默认设置DataFrame.join
是执行左连接(对于Excel用户来说基本上是“VLOOKUP”操作),它只使用在调用DataFrame中找到的键。其他连接类型(例如内连接)可以很容易地执行:
result = left.join(right, on=['key1', 'key2'], how='inner')
如您所见,这会丢弃任何没有匹配的行。
您可以加入单索引DataFrame
与多索引的级别DataFrame
。级别将匹配单索引帧的索引名称与多索引帧的级别名称。
left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
'B': ['B0', 'B1', 'B2']},
index=pd.Index(['K0', 'K1', 'K2'], name='key'))
index = pd.MultiIndex.from_tuples([('K0', 'Y0'), ('K1', 'Y1'),
('K2', 'Y2'), ('K2', 'Y3')],
names=['key', 'Y'])
right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']},
index=index)
result = left.join(right, how='inner')
这相当于但不那么冗长,内存效率更高/更快。
result = pd.merge(left.reset_index(), right.reset_index(),
on=['key'], how='inner').set_index(['key','Y'])
这不是通过join
现在实现的,但可以使用以下代码完成。
index = pd.MultiIndex.from_tuples([('K0', 'X0'), ('K0', 'X1'),
('K1', 'X2')],
names=['key', 'X'])
left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
'B': ['B0', 'B1', 'B2']},
index=index)
result = pd.merge(left.reset_index(), right.reset_index(),
on=['key'], how='inner').set_index(['key','X','Y'])
版本0.22中的新功能。
字符串作为传递on
,left_on
和right_on
参数可以指列名或索引级别名称。这样可以DataFrame
在不重置索引的情况下合并 索引级别和列的组合上的实例。
left_index = pd.Index(['K0', 'K0', 'K1', 'K2'], name='key1')
left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3'],
'key2': ['K0', 'K1', 'K0', 'K1']},
index=left_index)
right_index = pd.Index(['K0', 'K1', 'K2', 'K2'], name='key1')
right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3'],
'key2': ['K0', 'K0', 'K0', 'K1']},
index=right_index)
result = left.merge(right, on=['key1', 'key2'])
注意:当DataFrames合并到与两个帧中的索引级别匹配的字符串时,索引级别将保留为生成的DataFrame中的索引级别。
注意:如果字符串与列名称和索引级别名称都匹配,则会发出警告并且该列优先。这将导致未来版本中出现歧义错误。
merge suffixes
参数采用字符串列表的元组,以附加到输入DataFrame
s 中的重叠列名以消除结果列的歧义:
left = pd.DataFrame({'k': ['K0', 'K1', 'K2'], 'v': [1, 2, 3]})
right = pd.DataFrame({'k': ['K0', 'K0', 'K3'], 'v': [4, 5, 6]})
result = pd.merge(left, right, on='k')
result = pd.merge(left, right, on='k', suffixes=['_l', '_r'])
DataFrame.join()
有lsuffix
和rsuffix
行为相似的参数。
left = left.set_index('k')
right = right.set_index('k')
result = left.join(right, lsuffix='_l', rsuffix='_r')
DataFrames
也可以传递一个列表或元组,以便join()
在它们的索引上将它们连接在一起。
right2 = pd.DataFrame({'v': [7, 8, 9]}, index=['K1', 'K1', 'K2'])
result = left.join([right, right2])
另一个相当常见的情况是有两个类似索引(或类似索引)Series
或DataFrame
对象,并希望从一个对象中“修补”值,以匹配另一个对象中的索引。这是一个例子:
df1 = pd.DataFrame([[np.nan, 3., 5.], [-4.6, np.nan, np.nan],
[np.nan, 7., np.nan]])
df2 = pd.DataFrame([[-42.6, np.nan, -8.2], [-5., 1.6, 4]],
index=[1, 2])
为此,请使用以下combine_first()
方法:
result = df1.combine_first(df2)
请注意,DataFrame
如果左侧缺少值,则此方法仅从右侧获取值DataFrame
。一个相关的方法,update()
改变inplace中的非NA值:
df1.update(df2)
一个merge_ordered()
功能可以结合时间序列和其他有序的数据。特别是它有一个可选的fill_method
关键字来填充/插入缺失的数据:
left = pd.DataFrame({'k': ['K0', 'K1', 'K1', 'K2'],
'lv': [1, 2, 3, 4],
's': ['a', 'b', 'c', 'd']})
right = pd.DataFrame({'k': ['K1', 'K2', 'K4'],
'rv': [1, 2, 3]})
pd.merge_ordered(left, right, fill_method='ffill', left_by='s')
Out[122]:
k lv s rv
0 K0 1.0 a NaN
1 K1 1.0 a 1.0
2 K2 1.0 a 2.0
3 K4 1.0 a 3.0
4 K1 2.0 b 1.0
5 K2 2.0 b 2.0
6 K4 2.0 b 3.0
7 K1 3.0 c 1.0
8 K2 3.0 c 2.0
9 K4 3.0 c 3.0
10 K1 NaN d 1.0
11 K2 4.0 d 2.0
12 K4 4.0 d 3.0
版本0.19.0中的新功能。
A merge_asof()
类似于有序的左连接,除了我们匹配最近的键而不是相等的键。对于每一行left
DataFrame
,我们选择right
DataFrame
其on
键中小于左键的最后一行。两个DataFrame必须按键排序。
可选地,asof合并可以执行分组合并。这将匹配 by
键同样,除了在最近的比赛on
的关键。
例如; 我们可能有trades
并且quotes
我们想asof
合并它们。
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
Out[125]:
time ticker price quantity
0 2016-05-25 13:30:00.023 MSFT 51.95 75
1 2016-05-25 13:30:00.038 MSFT 51.95 155
2 2016-05-25 13:30:00.048 GOOG 720.77 100
3 2016-05-25 13:30:00.048 GOOG 720.92 100
4 2016-05-25 13:30:00.048 AAPL 98.00 100
quotes
Out[126]:
time ticker bid ask
0 2016-05-25 13:30:00.023 GOOG 720.50 720.93
1 2016-05-25 13:30:00.023 MSFT 51.95 51.96
2 2016-05-25 13:30:00.030 MSFT 51.97 51.98
3 2016-05-25 13:30:00.041 MSFT 51.99 52.00
4 2016-05-25 13:30:00.048 GOOG 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 GOOG 720.50 720.88
7 2016-05-25 13:30:00.075 MSFT 52.01 52.03
默认情况下,我们采用报价的asof。
pd.merge_asof(trades, quotes,
on='time',
by='ticker')
Out[127]:
time ticker price quantity bid ask
0 2016-05-25 13:30:00.023 MSFT 51.95 75 51.95 51.96
1 2016-05-25 13:30:00.038 MSFT 51.95 155 51.97 51.98
2 2016-05-25 13:30:00.048 GOOG 720.77 100 720.50 720.93
3 2016-05-25 13:30:00.048 GOOG 720.92 100 720.50 720.93
4 2016-05-25 13:30:00.048 AAPL 98.00 100 NaN NaN
我们只在2ms
报价时间和交易时间之间。
pd.merge_asof(trades, quotes,
on='time',
by='ticker',
tolerance=pd.Timedelta('2ms'))
Out[128]:
time ticker price quantity bid ask
0 2016-05-25 13:30:00.023 MSFT 51.95 75 51.95 51.96
1 2016-05-25 13:30:00.038 MSFT 51.95 155 NaN NaN
2 2016-05-25 13:30:00.048 GOOG 720.77 100 720.50 720.93
3 2016-05-25 13:30:00.048 GOOG 720.92 100 720.50 720.93
4 2016-05-25 13:30:00.048 AAPL 98.00 100 NaN NaN
我们仅在10ms
报价时间和交易时间之间,我们按时排除完全匹配。请注意,虽然我们排除了(引号的)完全匹配,但先前的引号会传播到该时间点。
pd.merge_asof(trades, quotes,
on='time',
by='ticker',
tolerance=pd.Timedelta('10ms'),
allow_exact_matches=False)
Out[129]:
time ticker price quantity bid ask
0 2016-05-25 13:30:00.023 MSFT 51.95 75 NaN NaN
1 2016-05-25 13:30:00.038 MSFT 51.95 155 51.97 51.98
2 2016-05-25 13:30:00.048 GOOG 720.77 100 NaN NaN
3 2016-05-25 13:30:00.048 GOOG 720.92 100 NaN NaN
4 2016-05-25 13:30:00.048 AAPL 98.00 100 NaN NaN
参考:http://pandas.pydata.org/pandas-docs/stable/merging.html#