繁华开满天机
在为自己回答这个问题的过程中,我学到了很多东西,我想把一组例子和一些解释放在一起。levels争论点的具体答案将走向终点。pandas.concat:失踪手册链接到当前文档导入和定义对象import pandas as pdd1 = 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 D2 0.1 0.2 0.3 NaN3 0.1 0.2 0.3 NaN1 NaN 0.4 0.5 0.62 NaN 0.4 0.5 0.6axis我们遇到的第二个参数是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 D2 0.1 0.2 0.3 NaN3 0.1 0.2 0.3 NaN1 NaN 0.4 0.5 0.62 NaN 0.4 0.5 0.6两个DataFrames的axis=1(并排)对于值1或columns我们的意思是说:“沿索引对齐并添加到列”,pd.concat([d1, d2], axis=1) A B C B C D1 NaN NaN NaN 0.4 0.5 0.62 0.1 0.2 0.3 0.4 0.5 0.63 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 13 2 | 3 2 | 3 2 | 3 21 3 | 1 3 | 1 3 | 1 32 4 | 2 4 | 2 4 | 2 4dtype: 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 Z1 NaN 3.0 | 1 NaN 3.0 | 1 NaN 3.0 5.02 1.0 4.0 | 2 1.0 4.0 | 2 1.0 4.0 NaN3 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 C2 1.0 NaN NaN NaN | 2 1.0 NaN NaN NaN3 2.0 NaN NaN NaN | 3 2.0 NaN NaN NaN2 NaN 0.1 0.2 0.3 | 2 NaN 0.1 0.2 0.33 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 C2 NaN NaN NaN 1.0 | 2 1.0 NaN NaN NaN | 2 NaN 1.0 NaN3 NaN NaN NaN 2.0 | 3 2.0 NaN NaN NaN | 3 NaN 2.0 NaN2 0.1 0.2 0.3 NaN | 2 NaN 0.1 0.2 0.3 | 2 0.1 0.2 0.33 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 C2 1 0.1 0.2 0.3 | 1 NaN 3.0 5.0 NaN NaN NaN3 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.3join第三个参数是join描述生成的合并是应该是外部合并(默认)还是内部合并。join:{'inner','outer'},默认'outer' 如何处理其他轴上的索引。事实证明,没有left或right选项pd.concat可以处理多于两个要合并的对象。在的情况下,d1和d2,选项如下所示:outerpd.concat([d1, d2], axis=1, join='outer') A B C B C D1 NaN NaN NaN 0.4 0.5 0.62 0.1 0.2 0.3 0.4 0.5 0.63 0.1 0.2 0.3 NaN NaN NaNinnerpd.concat([d1, d2], axis=1, join='inner') A B C B C D2 0.1 0.2 0.3 0.4 0.5 0.6join_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 D2 0.1 0.2 0.3 0.4 0.5 0.6 NaN NaN NaN3 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 D1 NaN NaN NaN 0.4 0.5 0.6 0.7 0.8 0.93 0.1 0.2 0.3 NaN NaN NaN 0.7 0.8 0.9ignore_indexignore_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 D2 0.1 0.2 0.3 NaN | 0 0.1 0.2 0.3 NaN | 0 0.1 0.2 0.3 NaN3 0.1 0.2 0.3 NaN | 1 0.1 0.2 0.3 NaN | 1 0.1 0.2 0.3 NaN1 NaN 0.4 0.5 0.6 | 2 NaN 0.4 0.5 0.6 | 2 NaN 0.4 0.5 0.62 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 51 NaN NaN NaN 0.4 0.5 0.6 | 1 NaN NaN NaN 0.4 0.5 0.62 0.1 0.2 0.3 0.4 0.5 0.6 | 2 0.1 0.2 0.3 0.4 0.5 0.63 0.1 0.2 0.3 NaN NaN NaN | 3 0.1 0.2 0.3 NaN NaN NaNkeys我们可以传递标量值或元组列表,以便将元组或标量值分配给相应的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 2B 1 3 B 1 3 2 4 2 4C 1 5 dtype: int64 3 6dtype: 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 4B X 1 5 3 6dtype: int64axis=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 Y1 NaN 3.0 | 1 NaN 3.0 | 1 NaN 3.0 | 1 NaN 3.02 1.0 4.0 | 2 1.0 4.0 | 2 1.0 4.0 | 2 1.0 4.03 2.0 NaN | 3 2.0 NaN | 3 2.0 NaN | 3 2.0 NaNMultiIndex用Series和axis=1 pd.concat( [s1, s2], axis=1, keys=[('W', 'X'), ('W', 'Y')])----------------------------------- W X Y1 NaN 3.02 1.0 4.03 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 X1 NaN NaN NaN 0.4 0.5 0.6 | A B C B C D2 0.1 0.2 0.3 0.4 0.5 0.6 | 1 NaN NaN NaN 0.4 0.5 0.63 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 NaNSeries并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 C2 1 0.1 0.2 0.3 | 2 1 0.1 0.2 0.33 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 C2 0.1 0.2 0.33 0.1 0.2 0.3然后将其与另一个数据框连接在一起,而对象中只有一个级别,Pandas将拒绝尝试创建MultiIndex对象的元组并组合所有数据框,就像单个级别的对象,标量和元组一样。pd.concat([d1_, d2], axis=1) (One, A) (One, B) (One, C) B C D1 NaN NaN NaN 0.4 0.5 0.62 0.1 0.2 0.3 0.4 0.5 0.63 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 10 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.61 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 NaNlevels这与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 D1 NaN NaN NaN 0.4 0.5 0.6 0.7 0.8 0.92 0.1 0.2 0.3 0.4 0.5 0.6 NaN NaN NaN3 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 Second1 0.0 2.4 1.52 0.6 0.0 1.53 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 Second1 0.0 2.4 1.52 0.6 0.0 1.53 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 Fifth1 0.0 1.5 0.0 2.4 0.02 0.6 1.5 0.0 0.0 0.03 0.6 0.0 0.0 2.4 0.0names这用于命名结果的级别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 1lvl0 lvl1 | lvl1 A B C B C D0 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.61 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 D2 0.1 0.2 0.3 NaN3 0.1 0.2 0.3 NaN1 NaN 0.4 0.5 0.62 NaN 0.4 0.5 0.6和pd.concat([d1, d2], verify_integrity=True)> ValueError:索引具有重叠值:[2]