为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

翻翻过去那场雪 2019-08-30 14:51:04
问题我该怎么用pd.concat?是什么意思levels?是什么意思keys?是否有一些示例来帮助解释如何使用所有参数?熊猫的concat功能是合并公用事业的瑞士军刀。它有用的各种情况很多。现有文档遗漏了一些可选参数的一些细节。其中包括levels和keys论点。我开始弄清楚这些论点的作用。我将提出一个问题,它将成为许多方面的门户pd.concat。考虑数据帧d1,d2以及d3:import pandas as pdd1 = 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.MultiIndexfor my columns对象的预期结果:        A    B    C    Dd1 2  0.1  0.2  0.3  NaN   3  0.1  0.2  0.3  NaNd2 1  NaN  0.4  0.5  0.6   2  NaN  0.4  0.5  0.6d3 1  0.7  0.8  NaN  0.9   3  0.7  0.8  NaN  0.9但是,我想使用levelsargmument文档:级别:序列列表,默认为无。用于构造MultiIndex的特定级别(唯一值)。否则,它们将从键中推断出来。所以我通过了pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'], levels=[['d1', 'd2']])得到一个 KeyErrorValueError: 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。
查看完整描述

2 回答

?
繁华开满天机

TA贡献1816条经验 获得超4个赞

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


levels争论点的具体答案将走向终点。


pandas.concat:失踪手册

链接到当前文档


导入和定义对象

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


我们通常会看到这与一个Series或多个DataFrame对象一起使用。

我将展示它dict也非常有用。

发电机也可使用,并使用时可以是有用的map,如map(f, list_of_df)

现在,我们将坚持上面定义的一些DataFrame和Series对象的列表。我将展示如何利用字典来提供非常有用的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:


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


两个DataFrame带axis=0(堆叠)

对于0或index我们的意思是说:“沿着列对齐并添加到索引”。


如上所示我们使用的地方axis=0,因为0是默认值,我们看到索引d2扩展了索引,d1尽管价值重叠2:


pd.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

两个DataFrames的axis=1(并排)

对于值1或columns我们的意思是说:“沿索引对齐并添加到列”,


pd.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列d2。


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

当结合pandas.Series一起axis=0,我们得到一个pandas.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=1(并排)

在组合pandas.Series时axis=1,它是name我们引用的属性,以便在结果中推断列名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并DataFrame用axis=0(堆叠)

当执行a Series和DataFramealong 的串联时axis=0,我们将所有转换Series为单列DataFrames。


请特别注意,这是一个串联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控制结果列的名称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并DataFrame用axis=1(并排)

这非常直观。当属性不可用时,Series列名默认为此类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描述生成的合并是应该是外部合并(默认)还是内部合并。


join:{'inner','outer'},默认'outer' 

如何处理其他轴上的索引。


事实证明,没有left或right选项pd.concat可以处理多于两个要合并的对象。


在的情况下,d1和d2,选项如下所示:


outer

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合并的事情。


join_axes:索引对象列表

用于其他n - 1轴而不是执行内部/外部设置逻辑的特定索引。


左合并

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

合并

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

ignore_index:boolean,default False 

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


就像我堆叠在一起d1时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

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


keys:sequence,default None 

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


axis=0

连接Series对象时axis=0(扩展索引)。


这些键成为MultiIndexindex属性中对象的新初始级别。


 #           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属性。


两个的变化Serieswtihaxis=1

请注意,只要没有传递就命名s1和s2事务keys,但如果keys传递则会被覆盖。


               |                       |                        |  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=0示例一样,keys将级别添加到a 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=1

这很棘手。在这种情况下,标量密钥值不能充当索引为唯一的水平Series时,它成为一列,同时还充当的第一级对象MultiIndex的DataFrame。因此,Pandas将再次使用对象的name属性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和MultiIndex差异。

Pandas似乎只是从Series名称推断列名,但在具有不同列级别的数据帧之间进行类似级联时,它不会填充空白。


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

然后将其与另一个数据框连接在一起,而对象中只有一个级别,Pandas将拒绝尝试创建MultiIndex对象的元组并组合所有数据框,就像单个级别的对象,标量和元组一样。


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,Pandas将获取结果的每个级别的唯一值MultiIndex,并将其用作结果index.levels属性中使用的对象。


级别:序列列表,默认无

用于构造MultiIndex的特定级别(唯一值)。否则,它们将从键中推断出来。


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


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


考虑作为df串联的数据框d1,d2并且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']其他缺少的类别命名Third和Fifth?我希望它们包含在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

但是column对象的第一级是:


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。


names:list,default无

生成的层次结构索引中的级别的名称


 # 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:boolean,default False 

检查新的连锁轴是否包含重复项。相对于实际数据连接,这可能非常昂贵。


因为从串联结果索引d1和d2不唯一,它会失败的完整性检查。


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]


查看完整回答
反对 回复 2019-08-30
?
森林海

TA贡献2011条经验 获得超2个赞

对于社区而言,简单地执行拉取请求以向主文档添加一些缺少的示例(仅一对)真的会更有用; SO只能搜索而不能浏览; 进一步建立文档的链接在这里很有用 - 绝大多数已经很好并且完全记录在案 

查看完整回答
反对 回复 2019-08-30
  • 2 回答
  • 0 关注
  • 1589 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信