【Pandas】数据合并和连接
发布日期:2021-09-18 21:55:44 浏览次数:2 分类:技术文章

本文共 22236 字,大约阅读时间需要 74 分钟。

pandas提供了各种工具,可以在连接/合并类型操作的情况下,轻松地将Series,DataFrame和Panel对象与索引和关系代数功能的各种设置逻辑组合在一起。

目录

 

连接对象

该函数(在主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)

_images / merging_concat_basic.png

像ndarrays其兄弟功能numpy.concatenatepandas.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'])

_images / merging_concat_keys.png

如您所见(如果您已阅读其余文档),结果对象的索引具有。这意味着我们现在可以按键选择每个块:

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

看看它如何非常有用并不是一件容易的事。有关此功能的更多细节如下。

注意:值得注意的是(并因此 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

一个有用的快捷方式是 实例方法SeriesDataFrame。这些方法实际上早于此 concat。它们连接在一起axis=0,即索引:

result = df1.append(df2)
 

 

在这种情况下DataFrame,索引必须是不相交的,但列不需要是:

result = df1.append(df4)
 

 

append 可能需要多个对象连接:

result = df1.append([df2, df3])
 

注意:与append()附加到原始列表并返回的方法不同None, 此处不会修改 df1并返回其df2附加的副本。

 

忽略连接轴上的索引

对于DataFrame没有有意义索引的s,您可能希望附加它们并忽略它们可能具有重叠索引的事实。为此,请使用以下ignore_index参数:

result = pd.concat([df1, df4], ignore_index=True)
 

 

这也是一个有效的论据:

result = df1.append(df4, ignore_index=True)
 

 

与混合ndims连接

你可以连接SeriesDataFrames 的混合。该 Series会转化为DataFrame与列名的名称Series

s1 = pd.Series(['X0', 'X1', 'X2', 'X3'], name='X')result = pd.concat([df1, s1], axis=1)
 

 

注意:由于我们将a连接Series到a DataFrame,因此我们可以获得相同的结果。要连接任意数量的pandas对象(DataFrameSeries),请使用 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时覆盖列名。请注意默认行为如何让结果 继承父名称(当存在时)。DataFrameSeriesDataFrameSeries

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  10    0  0  01    1  1  12    2  2  43    3  3  5

通过keys参数,我们可以覆盖现有的列名。

pd.concat([s3, s4, s5], axis=1, keys=['red','blue','yellow'])
Out[26]:    red  blue  yellow0    0     0       01    1     1       12    2     2       43    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)
 

 

数据库风格的DataFrame加入/合并

pandas具有功能齐全的高性能内存中连接操作,与SQL等关系数据库非常相似。与其他开源实现(如base::merge.data.frame R中)相比,这些方法的性能明显更好(在某些情况下甚至超过了一个数量级)。原因是仔细的算法设计和数据的内部布局DataFrame

有关一些高级策略,请参阅。

熟悉SQL但对pandas不熟悉的用户可能会对感兴趣 。

pandas提供单个函数,作为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_indexFalse在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是否为指定类型。

    • “one_to_one”或“1:1”:检查合并键是否在左右数据集中都是唯一的。
    • “one_to_many”或“1:m”:检查合并键是否在左数据集中是唯一的。
    • “many_to_one”或“m:1”:检查合并键在右侧数据集中是否唯一。
    • “many_to_many”或“m:m”:允许,但不会导致检查。

    版本0.21.0中的新功能。

注意:用于指定索引水平支撑onleft_on以及 right_on在0.23.0版加入参数。

返回类型将与left。相同。如果leftDataFrame 并且right是DataFrame的子类,则返回类型仍然是 DataFrame

merge是pandas命名空间中的一个函数,它也可以作为 DataFrame实例方法使用,调用 DataFrame被隐式地视为连接中的左对象。

相关方法,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')
 

这是一个包含多个连接键的更复杂的示例。默认情况下,只有出现在leftright存在的键(交叉点) 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_y0    1  1  NaN1    2  2  4.02    2  2  5.03    2  2  6.0

 

合并指标

接受这个论点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      _merge0     0        a        NaN   left_only1     1        b        2.0        both2     2      NaN        2.0  right_only3     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_column0     0        a        NaN        left_only1     1        b        2.0             both2     2      NaN        2.0       right_only3     2      NaN        2.0       right_only

 

合并Dtypes 

版本0.19.0中的新功能。

合并将保留连接键的dtype。

left = pd.DataFrame({'key': [1], 'v1': [10]})left
Out[59]:    key  v10    1  10
right = pd.DataFrame({'key': [1, 2], 'v1': [20, 30]})right
Out[61]:    key  v10    1  201    2  30

我们可以保留连接键:

pd.merge(left, right, how='outer')
Out[62]:    key  v10    1  101    1  202    2  30
pd.merge(left, right, how='outer').dtypes
Out[63]: key    int64v1     int64dtype: object

当然,如果您缺少引入的值,则生成的dtype将是upcast。

pd.merge(left, right, how='outer', on='key')
Out[64]:    key  v1_x  v1_y0    1  10.0    201    2   NaN    30
pd.merge(left, right, how='outer', on='key').dtypes
Out[65]: key       int64v1_x    float64v1_y      int64dtype: object

版本0.20.0中的新功能。

合并将保留categorymergands的dtypes。另请参阅有关的部分。

左框架。

from pandas.api.types import CategoricalDtypeX = 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      Y0  bar    one1  foo    one2  foo  three3  bar  three4  foo    one5  bar    one6  bar  three7  bar  three8  bar  three9  foo  three
left.dtypes
Out[71]: X    categoryY      objectdtype: object

正确的框架。

right = pd.DataFrame({ 'X': pd.Series(['foo', 'bar'],                dtype=CategoricalDtype(['foo', 'bar'])), 'Z': [1, 2]})
right
Out[73]:      X  Z0  foo  11  bar  2
right.dtypes
Out[74]: X    categoryZ       int64dtype: object

合并后的结果:

result = pd.merge(left, right, how='outer')result
Out[76]:      X      Y  Z0  bar    one  21  bar  three  22  bar    one  23  bar  three  24  bar  three  25  bar  three  26  foo    one  17  foo  three  18  foo    one  19  foo  three  1
result.dtypes
Out[77]: X    categoryY      objectZ       int64dtype: object

注意:类别dtypes必须完全相同,即相同的类别和有序属性。否则结果将强制转换为objectdtype。

注意:与categorydtype 合并相比,在相同的dtypes上合并可以非常高效object

 

加入索引

是一种方便的方法,用于将两个可能不同索引的列组合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')
 

_images / merging_join_outer.png

与上面相同,但有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');
 

 

连接索引上的键列

获取一个可选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);

_images / merging_join_key_columns.png

_images / merging_merge_key_columns.png

要连接多个键,传递的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'])
 

_images / merging_merge_multiindex_alternative.png

 

加入两个多索引

这不是通过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中的新功能。

字符串作为传递onleft_onright_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参数采用字符串列表的元组,以附加到输入DataFrames 中的重叠列名以消除结果列的歧义:

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'])
 

lsuffixrsuffix行为相似的参数。

left = left.set_index('k') right = right.set_index('k') result = left.join(right, lsuffix='_l', rsuffix='_r')
 

 

连接多个DataFrame或Panel对象

DataFrames也可以传递一个列表或元组,以便 在它们的索引上将它们连接在一起。

right2 = pd.DataFrame({'v': [7, 8, 9]}, index=['K1', 'K1', 'K2'])result = left.join([right, right2])
 

 

将Series或DataFrame列中的值合并在一起

另一个相当常见的情况是有两个类似索引(或类似索引)SeriesDataFrame对象,并希望从一个对象中“修补”值,以匹配另一个对象中的索引。这是一个例子:

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])

为此,请使用以下方法:

result = df1.combine_first(df2)
 

 

请注意,DataFrame如果左侧缺少值,则此方法仅从右侧获取值DataFrame。一个相关的方法,改变inplace中的非NA值:

df1.update(df2)
 

 

 

时间序列友好合并

合并有序数据

一个功能可以结合时间序列和其他有序的数据。特别是它有一个可选的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   rv0   K0  1.0  a  NaN1   K1  1.0  a  1.02   K2  1.0  a  2.03   K4  1.0  a  3.04   K1  2.0  b  1.05   K2  2.0  b  2.06   K4  2.0  b  3.07   K1  3.0  c  1.08   K2  3.0  c  2.09   K4  3.0  c  3.010  K1  NaN  d  1.011  K2  4.0  d  2.012  K4  4.0  d  3.0

 

合并ASOF 

版本0.19.0中的新功能。

A 类似于有序的左连接,除了我们匹配最近的键而不是相等的键。对于每一行left DataFrame,我们选择right DataFrameon键中小于左键的最后一行。两个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  quantity0 2016-05-25 13:30:00.023   MSFT   51.95        751 2016-05-25 13:30:00.038   MSFT   51.95       1552 2016-05-25 13:30:00.048   GOOG  720.77       1003 2016-05-25 13:30:00.048   GOOG  720.92       1004 2016-05-25 13:30:00.048   AAPL   98.00       100
quotes
Out[126]:                      time ticker     bid     ask0 2016-05-25 13:30:00.023   GOOG  720.50  720.931 2016-05-25 13:30:00.023   MSFT   51.95   51.962 2016-05-25 13:30:00.030   MSFT   51.97   51.983 2016-05-25 13:30:00.041   MSFT   51.99   52.004 2016-05-25 13:30:00.048   GOOG  720.50  720.935 2016-05-25 13:30:00.049   AAPL   97.99   98.016 2016-05-25 13:30:00.072   GOOG  720.50  720.887 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     ask0 2016-05-25 13:30:00.023   MSFT   51.95        75   51.95   51.961 2016-05-25 13:30:00.038   MSFT   51.95       155   51.97   51.982 2016-05-25 13:30:00.048   GOOG  720.77       100  720.50  720.933 2016-05-25 13:30:00.048   GOOG  720.92       100  720.50  720.934 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     ask0 2016-05-25 13:30:00.023   MSFT   51.95        75   51.95   51.961 2016-05-25 13:30:00.038   MSFT   51.95       155     NaN     NaN2 2016-05-25 13:30:00.048   GOOG  720.77       100  720.50  720.933 2016-05-25 13:30:00.048   GOOG  720.92       100  720.50  720.934 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    ask0 2016-05-25 13:30:00.023   MSFT   51.95        75    NaN    NaN1 2016-05-25 13:30:00.038   MSFT   51.95       155  51.97  51.982 2016-05-25 13:30:00.048   GOOG  720.77       100    NaN    NaN3 2016-05-25 13:30:00.048   GOOG  720.92       100    NaN    NaN4 2016-05-25 13:30:00.048   AAPL   98.00       100    NaN    NaN

 

参考:

转载地址:https://blog.csdn.net/ChenVast/article/details/82970464 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:【笔试面试】50+数据结构&算法问题
下一篇:【互联网软件设计风格】表现层状态转换(REST)

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月01日 19时07分15秒