在为自己回答这个问题的过程中,我学到了很多东西,我想整理一个例子和一些解释的目录。
针对题主的具体回答levels
争论将接近尾声。
pandas.concat
: 丢失的手册
链接到当前文档 https://pandas.pydata.org/pandas-docs/stable/generated/pandas.concat.html#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 对象的序列或映射
如果传递一个字典,则排序后的键将用作键参数,除非传递它,在这种情况下将选择值(见下文)。任何 None 对象都将被静默删除,除非它们都是 None 在这种情况下将引发 ValueError
- 我们通常会看到它与列表一起使用
Series
or DataFrame
对象。
- 我会证明这一点
dict
也可能非常有用。
- 也可以使用生成器,并且在使用时非常有用
map
as in map(f, list_of_df)
现在,我们将坚持列出一些DataFrame
and 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/'索引',1/'列'},默认0
沿其连接的轴。
Two DataFrame
s with axis=0
(堆叠)
对于值0
or 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
Two DataFrame
s with axis=1
(并排)
对于价值观1
or 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
with axis=0
(堆叠)
组合时pandas.Series
along 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
with axis=1
(并排)
组合时pandas.Series
along 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
Mixed Series
and DataFrame
with axis=0
(堆叠)
当执行串联时Series
and DataFrame
along axis=0
,我们将所有的Series
到单列DataFrame
s.
请特别注意,这是一个串联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
myself.
但是,我可以使用参数来控制结果列的名称to_frame
。重命名Series
与rename
方法确实not控制结果中的列名称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
Mixed Series
and DataFrame
with 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
or right
选项为pd.concat
可以处理多个要合并的对象。
如果是d1
and 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
合并等等。
连接轴:索引对象列表
用于其他 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
忽略索引: 布尔值,默认 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:顺序,默认 None
如果通过了多个级别,则应包含元组。使用传递的键作为最外层构建分层索引
axis=0
连接时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 的前面添加两个新的级别 aMultiIndex
:
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
属性。
Variations of Two
Series
wtih
axis=1
请注意,命名s1
and 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
with
Series
and
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
Two
DataFrame
with
axis=1
与axis=0
例子,keys
添加级别到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
and
DataFrame
with
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
Limitations of
keys
and
MultiIndex
inferrence.
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
属性。
levels:序列列表,默认 None
用于构造多重索引的特定级别(唯一值)。否则,将从密钥中推断出它们。
如果 Pandas 已经推断出这些级别应该是什么,那么我们自己指定它有什么好处呢?我将展示一个示例,然后让您思考为什么这可能有用的其他原因。
Example
根据文档,levels
参数是序列列表。这意味着我们可以使用另一个pandas.Index
作为这些序列之一。
考虑数据框df
这是串联的d1
, d2
and 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
we get:
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
and Fifth
?我希望它们包含在结果中groupby
聚合?如果我们有一个pandas.CategoricalIndex
。我们可以提前指定levels
争论。
因此,我们来定义df
as:
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')
And our 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:列表,默认无
生成的分层索引中级别的名称
# 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
不言自明的文档
验证完整性: 布尔值,默认 False
检查新的串联轴是否包含重复项。相对于实际的数据串联,这可能非常昂贵。
因为连接产生的索引d1
and 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
And
pd.concat([d1, d2], verify_integrity=True)
>
ValueError:索引具有重叠值:[2]