Pandas concat 函数中的“levels”、“keys”和“names”参数有什么用?
- 2025-01-17 09:23:00
- admin 原创
- 25
问题描述:
问题
我如何使用
pd.concat
?争论的焦点是什么
levels
?争论的焦点是什么
keys
?是否有大量示例可以帮助解释如何使用所有参数?
Pandasconcat
函数是合并实用程序中的瑞士军刀。它可用于多种情况。现有文档遗漏了一些可选参数的细节。其中包括levels
和keys
参数。我开始弄清楚这些参数的作用。
我将提出一个问题,它将成为了解的诸多方面的门户pd.concat
。
考虑数据框d1
、d2
和d3
:
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
参数文档:
levels:序列列表,默认为 None。用于构建 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:
在我自己回答这个问题的过程中,我学到了很多东西,我想整理一个示例目录和一些解释。
关于争论点的具体答案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 对象的序列或映射。如果传递了字典,则排序后的键将用作键参数,除非传递了字典,在这种情况下将选择值(见下文)。任何 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
:
轴:{0/'index',1/'columns'},默认 0 要连接的轴。
两个DataFrame
s 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
两个DataFrame
saxis=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'
SeriesSeries
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`
Series
当执行 a和DataFrame
along的连接时axis=0
,我们将全部转换Series
为单列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
并排)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
描述最终的合并应该是外合并(默认)还是内合并。
连接:{'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:Index 对象列表,
用于其他 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:布尔值,默认为 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
# /-------- /----------- # /---- /------\n 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=1Series
columns`
两种Series
变化axis=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
将级别添加到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
在成为列时不能充当对象的唯一索引级别,同时还不能充当第一级。因此,Pandas 将再次使用对象的属性作为MultiIndex
列名的来源。DataFrame
`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
。
级别:序列列表,默认无
用于构建多索引的特定级别(唯一值)。否则将从键中推断出它们。
如果 Pandas 已经推断出这些级别应该是什么,我们自己指定它有什么好处呢?我会举一个例子,然后你自己去想其他可能有用的原因。
例子
根据文档,该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='
')
Index(['First', 'Second', 'Fourth'], dtype='object')
Index(['A', 'B', 'C', 'D'], dtype='object')
如果我们使用sum
within a,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
但是列对象的第一级是:
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
检查新连接的轴是否包含重复项。相对于实际的数据连接,这可能非常昂贵。
由于连接得到的索引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]
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)