当前位置:   article > 正文

Python 数据处理 —— pandas 合并连接之 concat_python 实现group concat

python 实现group concat

前言

pandas 提供了各种工具,可以轻松地将不同的 SeriesDataFrame 连接、合并在一起

此外,pandas 还提供了比较两个 SeriesDataFrame 对象差异的实用工具

连接对象

concat() 函数能够沿指定轴执行连接操作,同时对其他轴上的索引(如果有的话,Series 只有一个轴)执行可选的集合运算(并集或交集)

下面是一个简单的示例

In [1]: 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],
   ...: )
   ...: 

In [2]: 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],
   ...: )
   ...: 

In [3]: 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],
   ...: )
   ...: 

In [4]: frames = [df1, df2, df3]

In [5]: result = pd.concat(frames)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

就像 ndarrays 上的函数 numpy.concatenate 一样,pandas.concat 接收一个相同类型的对象列表或字典,并通过一些配置来设置处理方式并将它们连接起来

pd.concat(
    objs,
    axis=0,
    join="outer",
    ignore_index=False,
    keys=None,
    levels=None,
    names=None,
    verify_integrity=False,
    copy=True,
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

让我们再来看看上面的例子。假设我们想将特定的键与被切割的 DataFrame 的每一个片段关联起来。我们可以使用 keys 参数来实现。

In [6]: result = pd.concat(frames, keys=["x", "y", "z"])
  • 1

从图中可以看出,在结果对象的索引的最外层添加了相应的索引(变为层次索引)。这意味着我们现在可以按键选择每个块

In [7]: result.loc["y"]
Out[7]: 
    A   B   C   D
4  A4  B4  C4  D4
5  A5  B5  C5  D5
6  A6  B6  C6  D6
7  A7  B7  C7  D7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

下面将详细介绍此功能

注意

concat()append() 都会对数据进行完整的复制,不断重复使用这个函数会造成显著的性能下降。

如果你想在多个数据集上执行该操作,可以使用列表推导式。

frames = [ process_your_file(f) for f in files ]
result = pd.concat(frames)
  • 1
  • 2

同时,当在指定轴上连接 DataFrames 时,pandas 将尽可能尝试保留这些索引或列名。

1 在其他轴上的设置逻辑

当将多个 DataFrame 连接在一起时,您可以通过以下两种方式来选择如何处理其他轴上的数据(即除被连接的轴外)。

  • 并集 join='outer',这是默认选项,因为它不会丢失信息
  • 交集 join='inner'

下面是这些方法的一个示例。首先,对于默认的 join='outer'

In [8]: df4 = pd.DataFrame(
   ...:     {
   ...:         "B": ["B2", "B3", "B6", "B7"],
   ...:         "D": ["D2", "D3", "D6", "D7"],
   ...:         "F": ["F2", "F3", "F6", "F7"],
   ...:     },
   ...:     index=[2, 3, 6, 7],
   ...: )
   ...: 

In [9]: result = pd.concat([df1, df4], axis=1)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

对于 join='inner' 也是一样的

In [10]: result = pd.concat([df1, df4], axis=1, join="inner")
  • 1

最后,假设我们只是想重用原始 DataFrame 中的确切索引

In [11]: result = pd.concat([df1, df4], axis=1).reindex(df1.index)
  • 1

类似地,我们可以在连接之前进行索引

In [12]: pd.concat([df1, df4.reindex(df1.index)], axis=1)
Out[12]: 
    A   B   C   D    B    D    F
0  A0  B0  C0  D0  NaN  NaN  NaN
1  A1  B1  C1  D1  NaN  NaN  NaN
2  A2  B2  C2  D2   B2   D2   F2
3  A3  B3  C3  D3   B3   D3   F3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2 使用 append 连接

SeriesDataFrame 上的 append() 实例方法是 concat() 的一个简单的快捷方式。

该方法实际上早于 concat。它沿着 axis=0 即索引方向进行连接

In [13]: result = df1.append(df2)
  • 1

DataFrame 中,索引必须是不相交的,但列不需要

In [14]: result = df1.append(df4, sort=False)
  • 1

append 可以接受多个对象来进行连接

In [15]: result = df1.append([df2, df3])
  • 1

注意

这里的 append() 方法不同于 list,该方法不会修改 df1 的值,同时返回是添加 df2 后的拷贝

3 忽略连接轴上的索引

对于某些 DataFrame 对象,其上的索引并没有任何意义,同时你可能希望在连接的时候,忽略这些对象的索引可能存在重叠的情况。

要做到这一点,可以使用 ignore_index 参数

In [16]: result = pd.concat([df1, df4], ignore_index=True, sort=False)
  • 1

这也是 DataFrame.append() 的一个有效参数

In [17]: result = df1.append(df4, ignore_index=True, sort=False)
  • 1

4 不同维度数据的连接

您也可以将 SeriesDataFrame 对象连接起来。Series 将被转换为 DataFrame,列名为 Series 的名称

In [18]: s1 = pd.Series(["X0", "X1", "X2", "X3"], name="X")

In [19]: result = pd.concat([df1, s1], axis=1)
  • 1
  • 2
  • 3

对于未命名的 Series,对应的列名将是连续增长的数字

In [20]: s2 = pd.Series(["_0", "_1", "_2", "_3"])

In [21]: result = pd.concat([df1, s2, s2, s2], axis=1)
  • 1
  • 2
  • 3

传递 ignore_index=True 将删除所有名称引用

In [22]: result = pd.concat([df1, s1], axis=1, ignore_index=True)
  • 1

5 使用 keys 连接

keys 参数的一个常见的用法是,基于现有 Series 创建新 DataFrame 时覆盖列名

默认的行为是如果 Series 的名称存在的话,让生成的 DataFrame 继承

In [23]: s3 = pd.Series([0, 1, 2, 3], name="foo")

In [24]: s4 = pd.Series([0, 1, 2, 3])

In [25]: s5 = pd.Series([0, 1, 4, 5])

In [26]: pd.concat([s3, s4, s5], axis=1)
Out[26]: 
   foo  0  1
0    0  0  0
1    1  1  1
2    2  2  4
3    3  3  5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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

In [27]: pd.concat([s3, s4, s5], axis=1, keys=["red", "blue", "yellow"])
Out[27]: 
   red  blue  yellow
0    0     0       0
1    1     1       1
2    2     2       4
3    3     3       5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

让我们考虑第一个例子的一个变体

In [28]: result = pd.concat(frames, keys=["x", "y", "z"])
  • 1

你也可以在 concat 中传递一个字典,在这种情况下,字典的键将用于 keys 参数(除非指定了其他键)

In [29]: pieces = {"x": df1, "y": df2, "z": df3}

In [30]: result = pd.concat(pieces)
  • 1
  • 2
  • 3

In [31]: result = pd.concat(pieces, keys=["z", "y"])
  • 1

结果中创建了 MultiIndex,最外层为 keys 参数指定的值,而原 DataFrame 的索引在内层保留了下来

In [32]: result.index.levels
Out[32]: FrozenList([['z', 'y'], [4, 5, 6, 7, 8, 9, 10, 11]])
  • 1
  • 2

如果你想指定其他级别,可以使用 levels 参数:

In [33]: result = pd.concat(
   ....:     pieces, keys=["x", "y", "z"], levels=[["z", "y", "x", "w"]], names=["group_key"]
   ....: )
   ....: 
  • 1
  • 2
  • 3
  • 4

In [34]: result.index.levels
Out[34]: FrozenList([['z', 'y', 'x', 'w'], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]])
  • 1
  • 2

6 将行追加到DataFrame

虽然这样做效率很低,但是你可以通过传递一个 Seriesdict 并将其追加到 DataFrame 中,同时会返回一个新的 DataFrame

In [35]: s2 = pd.Series(["X0", "X1", "X2", "X3"], index=["A", "B", "C", "D"])

In [36]: result = df1.append(s2, ignore_index=True)
  • 1
  • 2
  • 3

你应该使用 ignore_index 来指示 DataFrame 丢弃它的索引。

如果你希望保留索引,你应该为 DataFrame 构造一个合适的索引,然后追加或连接这些对象

你也可以传递字典或 Series 列表:

In [37]: dicts = [{"A": 1, "B": 2, "C": 3, "X": 4}, {"A": 5, "B": 6, "C": 7, "Y": 8}]

In [38]: result = df1.append(dicts, ignore_index=True, sort=False)
  • 1
  • 2
  • 3

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/75029
推荐阅读
相关标签
  

闽ICP备14008679号