Pandas的concat函数中的'levels','keys'和names参数是什么?

时间:2018-04-03 00:25:15

标签: python pandas

问题

  • 如何使用pd.concat
  • 什么是levels参数?
  • 什么是keys参数?
  • 是否有大量示例可帮助解释如何使用所有参数?

Pandas'concat函数是合并实用程序的Swiss Army knife。它有用的各种情况很多。现有文档遗漏了一些可选参数的一些细节。其中包括levelskeys个参数。我开始弄清楚这些论点是做什么的。

我将提出一个问题,作为pd.concat的许多方面的门户。

考虑数据框d1d2d3

import pandas as pd

d1 = pd.DataFrame(dict(A=.1, B=.2, C=.3), [2, 3])
d2 = pd.DataFrame(dict(B=.4, C=.5, D=.6), [1, 2])
d3 = pd.DataFrame(dict(A=.7, B=.8, D=.9), [1, 3])

如果我将这些与

连接在一起
pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'])

我的pandas.MultiIndex对象的columns获得了预期的结果:

        A    B    C    D
d1 2  0.1  0.2  0.3  NaN
   3  0.1  0.2  0.3  NaN
d2 1  NaN  0.4  0.5  0.6
   2  NaN  0.4  0.5  0.6
d3 1  0.7  0.8  NaN  0.9
   3  0.7  0.8  NaN  0.9

但是,我想使用levels argmument documentation

  

级别:序列列表,默认为无。   用于构造MultiIndex的特定级别(唯一值)。否则,它们将从键中推断出来。

所以我通过了

pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'], levels=[['d1', 'd2']])

获得KeyError

  

ValueError: Key d3 not in level Index(['d1', 'd2'], dtype='object')

这是有道理的。我通过的级别不足以描述键所指示的必要级别。如果我没有通过任何东西,就像我上面所做的那样,推断出水平(如文档中所述)。但是我怎么能用这个论点来更好地发挥作用呢?

如果我试过这个:

pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'], levels=[['d1', 'd2', 'd3']])

我得到了与上面相同的结果。但是当我再添加一个值时,

df = pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'], levels=[['d1', 'd2', 'd3', 'd4']])

我最终得到了相同的数据框,但结果MultiIndex有一个未使用的级别。

df.index.levels[0]

Index(['d1', 'd2', 'd3', 'd4'], dtype='object')

那么level参数的重点是什么?我应该以不同的方式使用keys吗?

我正在使用Python 3.6和Pandas 0.22。

1 个答案:

答案 0 :(得分:88)

在为自己回答这个问题的过程中,我学到了很多东西,我想把一些例子和一些解释放在一起。

levels论点的具体答案将会结束。

pandas.concat:失踪手册

Link To Current Documentation

导入和定义对象

import pandas as pd

d1 = pd.DataFrame(dict(A=.1, B=.2, C=.3), index=[2, 3])
d2 = pd.DataFrame(dict(B=.4, C=.5, D=.6), index=[1, 2])
d3 = pd.DataFrame(dict(A=.7, B=.8, D=.9), index=[1, 3])

s1 = pd.Series([1, 2], index=[2, 3])
s2 = pd.Series([3, 4], index=[1, 2])
s3 = pd.Series([5, 6], index=[1, 3])

参数

objs

我们遇到的第一个论点是 objs

  

objs :Series,DataFrame或Panel对象的序列或映射   如果传递了dict,则排序的键将用作keys参数,除非它被传递,在这种情况下将选择值(见下文)。任何None对象都将被静默删除,除非它们都是None,在这种情况下将引发ValueError

  • 我们通常会看到这与SeriesDataFrame个对象的列表一起使用。
  • 我将表明dict也非常有用。
  • 也可以使用生成器,在map中使用map(f, list_of_df)时非常有用

目前,我们将坚持上面定义的一些DataFrameSeries对象的列表。 我将展示如何利用字典来提供非常有用的MultiIndex结果。

pd.concat([d1, d2])

     A    B    C    D
2  0.1  0.2  0.3  NaN
3  0.1  0.2  0.3  NaN
1  NaN  0.4  0.5  0.6
2  NaN  0.4  0.5  0.6

axis

我们遇到的第二个论点是 axis ,其默认值为0

  

:{0 /'index',1 /'columns'},默认为0   要连接的轴。

两个DataFrameaxis=0(堆叠)

对于0index的值,我们的意思是:"沿着列对齐并添加到索引"。

如上所示我们使用了axis=0,因为0是默认值,我们看到d2的索引扩展了d1的索引,尽管有2pd.concat([d1, d2], axis=0) A B C D 2 0.1 0.2 0.3 NaN 3 0.1 0.2 0.3 NaN 1 NaN 0.4 0.5 0.6 2 NaN 0.4 0.5 0.6 重叠:

DataFrame

两个axis=11(并排)

对于值columnspd.concat([d1, d2], axis=1) A B C B C D 1 NaN NaN NaN 0.4 0.5 0.6 2 0.1 0.2 0.3 0.4 0.5 0.6 3 0.1 0.2 0.3 NaN NaN NaN ,我们的意思是:"沿着索引对齐并添加到列",

d1

我们可以看到结果索引是索引的并集,结果列是d2Series列的扩展名。

两个(或三个)axis=0pandas.Series(堆叠)

axis=0pandas.Series合并后,我们会返回Series。生成的None的名称将为Series,除非合并的所有'Name: A'具有相同的名称。当我们打印出结果Series时,请注意Series。如果不存在,我们可以假设None名称为 | | | pd.concat( | pd.concat( | pd.concat( | [s1.rename('A'), pd.concat( | [s1.rename('A'), | [s1.rename('A'), | s2.rename('B'), [s1, s2]) | s2]) | s2.rename('A')]) | s3.rename('A')]) -------------- | --------------------- | ---------------------- | ---------------------- 2 1 | 2 1 | 2 1 | 2 1 3 2 | 3 2 | 3 2 | 3 2 1 3 | 1 3 | 1 3 | 1 3 2 4 | 2 4 | 2 4 | 2 4 dtype: int64 | dtype: int64 | Name: A, dtype: int64 | 1 5 | | | 3 6 | | | dtype: int64

Series

两个(或三个)axis=1pandas.Series(并排)

axis=1name结合使用时,我们引用的pandas.DataFrame属性是为了在结果 | | pd.concat( | pd.concat( | [s1.rename('X'), pd.concat( | [s1.rename('X'), | s2.rename('Y'), [s1, s2], axis=1) | s2], axis=1) | s3.rename('Z')], axis=1) ---------------------- | --------------------- | ------------------------------ 0 1 | X 0 | X Y Z 1 NaN 3.0 | 1 NaN 3.0 | 1 NaN 3.0 5.0 2 1.0 4.0 | 2 1.0 4.0 | 2 1.0 4.0 NaN 3 2.0 NaN | 3 2.0 NaN | 3 2.0 NaN 6.0 中推断列名称。

Series

混合DataFrameaxis=0Series(已堆叠)

DataFrame上执行axis=0Series的串联时,我们会将所有DataFrame转换为单列axis=0

请特别注意,这是[2, 3, 2, 3]的连接;这意味着在对齐列时扩展索引(行)。在下面的例子中,我们看到索引变为Series,这是一个不加选择的索引追加。除非我强制使用to_frame的参数命名 pd.concat( | [s1.to_frame(), d1]) | pd.concat([s1, d1]) ------------------------- | --------------------- 0 A B C | 0 A B C 2 1.0 NaN NaN NaN | 2 1.0 NaN NaN NaN 3 2.0 NaN NaN NaN | 3 2.0 NaN NaN NaN 2 NaN 0.1 0.2 0.3 | 2 NaN 0.1 0.2 0.3 3 NaN 0.1 0.2 0.3 | 3 NaN 0.1 0.2 0.3 列,否则列不会重叠:

pd.concat([s1, d1])

您可以看到to_frame的结果与我自己打to_frame的结果相同。

但是,我可以使用Series的参数控制结果列的名称。使用rename方法重命名DataFrame 会控制生成的 # Effectively renames | | # `s1` but does not align | # Does not rename. So | # Renames to something # with columns in `d1` | # Pandas defaults to `0` | # that does align with `d1` pd.concat( | pd.concat( | pd.concat( [s1.to_frame('X'), d1]) | [s1.rename('X'), d1]) | [s1.to_frame('B'), d1]) ---------------------------- | -------------------------- | ---------------------------- A B C X | 0 A B C | A B C 2 NaN NaN NaN 1.0 | 2 1.0 NaN NaN NaN | 2 NaN 1.0 NaN 3 NaN NaN NaN 2.0 | 3 2.0 NaN NaN NaN | 3 NaN 2.0 NaN 2 0.1 0.2 0.3 NaN | 2 NaN 0.1 0.2 0.3 | 2 0.1 0.2 0.3 3 0.1 0.2 0.3 NaN | 3 NaN 0.1 0.2 0.3 | 3 0.1 0.2 0.3 中的列名。

Series

混合DataFrameaxis=1Series(并排)

这非常直观。当Series属性不可用时,name列名称默认为此类 | pd.concat( pd.concat( | [s1.rename('X'), [s1, d1], | s2, s3, d1], axis=1) | axis=1) ------------------- | ------------------------------- 0 A B C | X 0 1 A B C 2 1 0.1 0.2 0.3 | 1 NaN 3.0 5.0 NaN NaN NaN 3 2 0.1 0.2 0.3 | 2 1.0 4.0 NaN 0.1 0.2 0.3 | 3 2.0 NaN 6.0 0.1 0.2 0.3 个对象的枚举。

join

join

第三个参数是 left ,它描述了生成的合并是外部合并(默认)还是内部合并。

  

加入:{'内部','外部'},默认'外部'
  如何处理其他轴上的索引。

事实证明,没有rightpd.concat选项,因为d1只能处理两个要合并的对象。

如果是d2outer,则选项如下:

pd.concat([d1, d2], axis=1, join='outer') A B C B C D 1 NaN NaN NaN 0.4 0.5 0.6 2 0.1 0.2 0.3 0.4 0.5 0.6 3 0.1 0.2 0.3 NaN NaN NaN

inner

pd.concat([d1, d2], axis=1, join='inner') A B C B C D 2 0.1 0.2 0.3 0.4 0.5 0.6

join_axes

left

第四个论点是允许我们进行pd.concat([d1, d2, d3], axis=1, join_axes=[d1.index]) A B C B C D A B D 2 0.1 0.2 0.3 0.4 0.5 0.6 NaN NaN NaN 3 0.1 0.2 0.3 NaN NaN NaN 0.7 0.8 0.9 合并等的事情。

  

join_axes :索引对象列表
  用于其他n - 1轴的特定索引,而不是执行内部/外部设置逻辑。

左合并

pd.concat([d1, d2, d3], axis=1, join_axes=[d3.index])

     A    B    C    B    C    D    A    B    D
1  NaN  NaN  NaN  0.4  0.5  0.6  0.7  0.8  0.9
3  0.1  0.2  0.3  NaN  NaN  NaN  0.7  0.8  0.9

右合并

ignore_index

d1

  

ignore_index :布尔值,默认为False
  如果为True,请不要使用串联轴上的索引值。生成的轴将标记为0,...,n - 1.如果要连接并置轴没有有意义的索引信息的对象,这将非常有用。请注意,在连接中仍然遵循其他轴上的索引值。

就像我在d2之上堆叠 | pd.concat( | pd.concat( | [d1, d2], | [d1, d2] pd.concat([d1, d2]) | ignore_index=True) | ).reset_index(drop=True) --------------------- | ----------------------- | ------------------------- A B C D | A B C D | A B C D 2 0.1 0.2 0.3 NaN | 0 0.1 0.2 0.3 NaN | 0 0.1 0.2 0.3 NaN 3 0.1 0.2 0.3 NaN | 1 0.1 0.2 0.3 NaN | 1 0.1 0.2 0.3 NaN 1 NaN 0.4 0.5 0.6 | 2 NaN 0.4 0.5 0.6 | 2 NaN 0.4 0.5 0.6 2 NaN 0.4 0.5 0.6 | 3 NaN 0.4 0.5 0.6 | 3 NaN 0.4 0.5 0.6 一样,如果我不关心索引值,我可以重置它们或忽略它们。

axis=1

使用 | pd.concat( | [d1, d2], axis=1, pd.concat([d1, d2], axis=1) | ignore_index=True) ------------------------------- | ------------------------------- A B C B C D | 0 1 2 3 4 5 1 NaN NaN NaN 0.4 0.5 0.6 | 1 NaN NaN NaN 0.4 0.5 0.6 2 0.1 0.2 0.3 0.4 0.5 0.6 | 2 0.1 0.2 0.3 0.4 0.5 0.6 3 0.1 0.2 0.3 NaN NaN NaN | 3 0.1 0.2 0.3 NaN NaN NaN 时:

keys

axis=0

我们可以传递标量值或元组列表,以便将元组或标量值分配给相应的MultiIndex。传递列表的长度必须与要连接的项目数相同。

  

:序列,默认无

  如果传递了多个级别,则应包含元组。使用传递的键作为最外层

构造层次结构索引

Series

axis=0上连接MultiIndex个对象时(扩展索引)。

这些键成为索引属性中 # length 3 length 3 # length 2 length 2 # /--------\ /-----------\ # /----\ /------\ pd.concat([s1, s2, s3], keys=['A', 'B', 'C']) pd.concat([s1, s2], keys=['A', 'B']) ---------------------------------------------- ------------------------------------- A 2 1 A 2 1 3 2 3 2 B 1 3 B 1 3 2 4 2 4 C 1 5 dtype: int64 3 6 dtype: int64 对象的新初始级别。

keys

但是,我们可以在MultiIndex参数中使用多个标量值来创建更深的tuples。在这里,我们将长度为2的MultiIndex传递给 pd.concat( [s1, s2, s3], keys=[('A', 'X'), ('A', 'Y'), ('B', 'X')]) ----------------------------------------------- A X 2 1 3 2 Y 1 3 2 4 B X 1 5 3 6 dtype: int64 的前两个新级别:

axis=1

axis=0

沿列扩展时有点不同。当我们使用keys(参见上文)时,除了现有索引之外,我们的MultiIndex会充当axis=1级别。对于Series,我们指的是columns个对象没有的轴,即Series属性。

两个axis=1s1的变体

请注意,只要没有传递s2,就会keyskeys命名,但如果传递 | | | pd.concat( | pd.concat( | pd.concat( | [s1.rename('U'), pd.concat( | [s1, s2], | [s1.rename('U'), | s2.rename('V')], [s1, s2], | axis=1, | s2.rename('V')], | axis=1, axis=1) | keys=['X', 'Y']) | axis=1) | keys=['X', 'Y']) -------------- | --------------------- | ---------------------- | ---------------------- 0 1 | X Y | U V | X Y 1 NaN 3.0 | 1 NaN 3.0 | 1 NaN 3.0 | 1 NaN 3.0 2 1.0 4.0 | 2 1.0 4.0 | 2 1.0 4.0 | 2 1.0 4.0 3 2.0 NaN | 3 2.0 NaN | 3 2.0 NaN | 3 2.0 NaN 则会被覆盖。

MultiIndex
Series axis=1 pd.concat( [s1, s2], axis=1, keys=[('W', 'X'), ('W', 'Y')]) ----------------------------------- W X Y 1 NaN 3.0 2 1.0 4.0 3 2.0 NaN DataFrame
axis=1
两个axis=0keys

MultiIndex示例一样,columns pd.concat( | pd.concat( [d1, d2], | [d1, d2], axis=1, | axis=1, keys=['X', 'Y']) | keys=[('First', 'X'), ('Second', 'X')]) ------------------------------- | -------------------------------------------- X Y | First Second A B C B C D | X X 1 NaN NaN NaN 0.4 0.5 0.6 | A B C B C D 2 0.1 0.2 0.3 0.4 0.5 0.6 | 1 NaN NaN NaN 0.4 0.5 0.6 3 0.1 0.2 0.3 NaN NaN NaN | 2 0.1 0.2 0.3 0.4 0.5 0.6 | 3 0.1 0.2 0.3 NaN NaN NaN 添加级别,但这次是添加到Series属性中存储的对象。

DataFrame
axis=1Series MultiIndex

这很棘手。在这种情况下,标量键值在成为列时不能充当DataFrame对象的唯一索引级别,同时也充当name的{​​{1}}的第一级别。因此,Pandas将再次使用Series对象的 pd.concat( | pd.concat( [s1, d1], | [s1.rename('Z'), d1], axis=1, | axis=1, keys=['X', 'Y']) | keys=['X', 'Y']) --------------------- | -------------------------- X Y | X Y 0 A B C | Z A B C 2 1 0.1 0.2 0.3 | 2 1 0.1 0.2 0.3 3 2 0.1 0.2 0.3 | 3 2 0.1 0.2 0.3 属性作为列名的来源。

keys
MultiIndexSeries推论的局限性。

Pandas似乎只从d1_ = pd.concat( [d1], axis=1, keys=['One']) d1_ One A B C 2 0.1 0.2 0.3 3 0.1 0.2 0.3 名称推断出列名,但在具有不同列级别的数据帧之间进行类似级联时,它不会填补空白。

MultiIndex

然后将此与另一个数据框连接在一起,而对象中只有一个级别,Pandas将拒绝尝试生成pd.concat([d1_, d2], axis=1) (One, A) (One, B) (One, C) B C D 1 NaN NaN NaN 0.4 0.5 0.6 2 0.1 0.2 0.3 0.4 0.5 0.6 3 0.1 0.2 0.3 NaN NaN NaN 对象的元组并组合所有数据框,就像单个级别的对象,标量和元组。

dict

传递list而不是pandas.concat

传递字典时,keys会使用字典中的键作为 # axis=0 | # axis=1 pd.concat( | pd.concat( {0: d1, 1: d2}) | {0: d1, 1: d2}, axis=1) ----------------------- | ------------------------------- A B C D | 0 1 0 2 0.1 0.2 0.3 NaN | A B C B C D 3 0.1 0.2 0.3 NaN | 1 NaN NaN NaN 0.4 0.5 0.6 1 1 NaN 0.4 0.5 0.6 | 2 0.1 0.2 0.3 0.4 0.5 0.6 2 NaN 0.4 0.5 0.6 | 3 0.1 0.2 0.3 NaN NaN NaN 参数。

levels

keys

这与levels参数一起使用。当None保留为MultiIndex的默认值时,Pandas将采用结果{{的每个级别的唯一值1}}并将其用作生成的index.levels属性中使用的对象。

  

级别:序列列表,默认为无   用于构造MultiIndex的特定级别(唯一值)。否则,它们将从键中推断出来。

如果熊猫已经推断出这些水平应该是什么,那么我们有什么优势来指定它?我将展示一个示例,并让您自己想出其可能有用的其他原因。

实施例

根据文档,levels参数是序列列表。这意味着我们可以使用另一个pandas.Index作为其中一个序列。

考虑dfd1d2串联的数据框d3

df = pd.concat(
    [d1, d2, d3], axis=1,
    keys=['First', 'Second', 'Fourth'])

df

  First           Second           Fourth
      A    B    C      B    C    D      A    B    D
1   NaN  NaN  NaN    0.4  0.5  0.6    0.7  0.8  0.9
2   0.1  0.2  0.3    0.4  0.5  0.6    NaN  NaN  NaN
3   0.1  0.2  0.3    NaN  NaN  NaN    0.7  0.8  0.9

列对象的级别为:

print(df, *df.columns.levels, sep='\n')

Index(['First', 'Second', 'Fourth'], dtype='object')
Index(['A', 'B', 'C', 'D'], dtype='object')

如果我们在sum中使用groupby,我们会得到:

df.groupby(axis=1, level=0).sum()

   First  Fourth  Second
1    0.0     2.4     1.5
2    0.6     0.0     1.5
3    0.6     2.4     0.0

但是,如果不是['First', 'Second', 'Fourth']而是另一个名为ThirdFifth的缺失类别呢?我希望它们包含在groupby聚合的结果中?如果我们有pandas.CategoricalIndex,我们可以这样做。我们可以使用levels参数提前指定。

相反,让我们将df定义为:

cats = ['First', 'Second', 'Third', 'Fourth', 'Fifth']
lvl = pd.CategoricalIndex(cats, categories=cats, ordered=True)

df = pd.concat(
    [d1, d2, d3], axis=1,
    keys=['First', 'Second', 'Fourth'],
    levels=[lvl]
)

df

   First  Fourth  Second
1    0.0     2.4     1.5
2    0.6     0.0     1.5
3    0.6     2.4     0.0

但是对象的第一级是:

df.columns.levels[0]

CategoricalIndex(
    ['First', 'Second', 'Third', 'Fourth', 'Fifth'],
    categories=['First', 'Second', 'Third', 'Fourth', 'Fifth'],
    ordered=True, dtype='category')

我们的groupby总结如下:

df.groupby(axis=1, level=0).sum()

   First  Second  Third  Fourth  Fifth
1    0.0     1.5    0.0     2.4    0.0
2    0.6     1.5    0.0     0.0    0.0
3    0.6     0.0    0.0     2.4    0.0

names

这用于命名结果MultiIndex的级别。 names列表的长度应与结果MultiIndex中的级别数相匹配。

  

名称:列表,默认无   生成的分层索引中的级别名称

 # axis=0                     |  # axis=1
 pd.concat(                   |  pd.concat(
     [d1, d2],                |      [d1, d2],
     keys=[0, 1],             |      axis=1, keys=[0, 1],
     names=['lvl0', 'lvl1'])  |      names=['lvl0', 'lvl1'])
----------------------------- | ----------------------------------
             A    B    C    D | lvl0    0              1
lvl0 lvl1                     | lvl1    A    B    C    B    C    D
0    2     0.1  0.2  0.3  NaN | 1     NaN  NaN  NaN  0.4  0.5  0.6
     3     0.1  0.2  0.3  NaN | 2     0.1  0.2  0.3  0.4  0.5  0.6
1    1     NaN  0.4  0.5  0.6 | 3     0.1  0.2  0.3  NaN  NaN  NaN
     2     NaN  0.4  0.5  0.6 |

verify_integrity

自我解释性文件

  

verify_integrity :布尔值,默认为False
  检查新的连锁轴是否包含重复项。相对于实际的数据连接,这可能非常昂贵。

因为连接d1d2的结果索引不是唯一的,所以它将无法通过完整性检查。

pd.concat([d1, d2])

     A    B    C    D
2  0.1  0.2  0.3  NaN
3  0.1  0.2  0.3  NaN
1  NaN  0.4  0.5  0.6
2  NaN  0.4  0.5  0.6

pd.concat([d1, d2], verify_integrity=True)

>     ValueError:索引具有重叠值:[2]