在 pandas MultiIndex 级别广播,即使索引值恰好一致
Broadcast across pandas MultiIndex level even if index values happen to agree
这个让我难住了。我有两个 pd.Series
s
和 t
如下:
Common Level s
Foo a 1
b 2
Name: s, dtype: int64
Common Level t
Foo A 10
B 20
Name: t, dtype: int64
pandas
让我添加这些并在公共级别进行广播 'Common'
输入:
s + t
输出:
Common Level s Level t
Foo a A 11
B 21
b A 12
B 22
dtype: int64
现在考虑另一个 pd.Series
u
,其中索引 labels 恰好与 s
的索引一致
Common Level u
Foo a 100
b 200
Name: u, dtype: int64
换句话说,我们有(s.index.values == u.index.values).all()
returns True
。因此,pandas
不再广播
输入:
s + u
输出:
Common Level s
Foo a 101
b 202
dtype: int64
尽管 s.index.names
和 u.index.names
不同意。
最后,如果更改了顺序但没有更改标签,例如 v
:
Common Level v
Foo b 1000
a 2000
Name: v, dtype: int64
所以 s.index.values
和 v.index.values
不完全一致,然后广播发生。
输入:
s + v
输出:
Common Level s Level v
Foo a b 1001
a 2001
b b 1002
a 2002
dtype: int64
我的问题:如何添加 s
和 u
以便 pandas
仍然广播? (对于我的特定应用程序,我实际上对 elementwise-and s & u
感兴趣,而不是总和 s + u
。)
代码
s = pd.Series([1, 2],
index=pd.MultiIndex.from_tuples(
[('Foo', 'a'), ('Foo', 'b')],
names=['Common', 'Level s']), name='s')
t = pd.Series([10, 20],
index=pd.MultiIndex.from_tuples(
[('Foo', 'A'), ('Foo', 'B')],
names=['Common', 'Level t']), name='t')
u = pd.Series([100, 200],
index=pd.MultiIndex.from_tuples(
[('Foo', 'a'), ('Foo', 'b')],
names=['Common', 'Level u']), name='u')
v = pd.Series([1000, 2000],
index=pd.MultiIndex.from_tuples(
[('Foo', 'b'), ('Foo', 'a')],
names=['Common', 'Level v']), name='v')
为广播规范化Series和DataFrame的索引调用的方法是align
。此方法在内部调用以获取新索引,我们可以看到:
left, right = s.align(t, join='outer', level=None, copy=False)
# left
Common Level s Level t
Foo a A 1
B 1
b A 2
B 2
Name: s, dtype: int64
# right
Common Level s Level t
Foo a A 10
B 20
b A 10
B 20
Name: t, dtype: int64
请注意,当索引相等时,此调用将生成“非广播”值,因为外部联接生成单个级别:
left, right = s.align(u, join='outer', level=None, copy=False)
# left
Common Level s
Foo a 1
b 2
Name: s, dtype: int64
# right
Common Level u
Foo a 100
b 200
Name: u, dtype: int64
如果我们想强制生成级别,我们可以使用 _align_series
中的分支来处理索引不相等的情况:
join_index, lidx, ridx = self.index.join(
other.index, how=join, level=level, return_indexers=True
)
left = self._reindex_indexer(join_index, lidx, copy)
right = other._reindex_indexer(join_index, ridx, copy)
我们可以使用 Index.join
和 _reindex_indexer
来创建对齐系列:
join_index, lidx, ridx = s.index.join(
u.index, how='outer', level=None, return_indexers=True
)
left = s._reindex_indexer(join_index, lidx, copy=False)
right = u._reindex_indexer(join_index, ridx, copy=False)
*注意:我们正在使用私有方法,因为 public API.
中没有等效的重新索引器
现在我们已经对齐系列了,我们可以这样做:
left + right
获取结果:
Common Level s Level u
Foo a a 101
b 201
b a 102
b 202
dtype: int64
如果我们想避免使用私有方法,我们也可以iloc
to select values using index locations then set_axis
用带有适当标签的连接索引覆盖:
join_index, lidx, ridx = s.index.join(
u.index, how='outer', level=None, return_indexers=True
)
left = s.iloc[lidx].set_axis(join_index)
right = u.iloc[ridx].set_axis(join_index)
left + right
Common Level s Level u
Foo a a 101
b 201
b a 102
b 202
dtype: int64
这个让我难住了。我有两个 pd.Series
s
和 t
如下:
Common Level s
Foo a 1
b 2
Name: s, dtype: int64
Common Level t
Foo A 10
B 20
Name: t, dtype: int64
pandas
让我添加这些并在公共级别进行广播 'Common'
输入:
s + t
输出:
Common Level s Level t
Foo a A 11
B 21
b A 12
B 22
dtype: int64
现在考虑另一个 pd.Series
u
,其中索引 labels 恰好与 s
Common Level u
Foo a 100
b 200
Name: u, dtype: int64
换句话说,我们有(s.index.values == u.index.values).all()
returns True
。因此,pandas
不再广播
输入:
s + u
输出:
Common Level s
Foo a 101
b 202
dtype: int64
尽管 s.index.names
和 u.index.names
不同意。
最后,如果更改了顺序但没有更改标签,例如 v
:
Common Level v
Foo b 1000
a 2000
Name: v, dtype: int64
所以 s.index.values
和 v.index.values
不完全一致,然后广播发生。
输入:
s + v
输出:
Common Level s Level v
Foo a b 1001
a 2001
b b 1002
a 2002
dtype: int64
我的问题:如何添加 s
和 u
以便 pandas
仍然广播? (对于我的特定应用程序,我实际上对 elementwise-and s & u
感兴趣,而不是总和 s + u
。)
代码
s = pd.Series([1, 2],
index=pd.MultiIndex.from_tuples(
[('Foo', 'a'), ('Foo', 'b')],
names=['Common', 'Level s']), name='s')
t = pd.Series([10, 20],
index=pd.MultiIndex.from_tuples(
[('Foo', 'A'), ('Foo', 'B')],
names=['Common', 'Level t']), name='t')
u = pd.Series([100, 200],
index=pd.MultiIndex.from_tuples(
[('Foo', 'a'), ('Foo', 'b')],
names=['Common', 'Level u']), name='u')
v = pd.Series([1000, 2000],
index=pd.MultiIndex.from_tuples(
[('Foo', 'b'), ('Foo', 'a')],
names=['Common', 'Level v']), name='v')
为广播规范化Series和DataFrame的索引调用的方法是align
。此方法在内部调用以获取新索引,我们可以看到:
left, right = s.align(t, join='outer', level=None, copy=False)
# left
Common Level s Level t
Foo a A 1
B 1
b A 2
B 2
Name: s, dtype: int64
# right
Common Level s Level t
Foo a A 10
B 20
b A 10
B 20
Name: t, dtype: int64
请注意,当索引相等时,此调用将生成“非广播”值,因为外部联接生成单个级别:
left, right = s.align(u, join='outer', level=None, copy=False)
# left
Common Level s
Foo a 1
b 2
Name: s, dtype: int64
# right
Common Level u
Foo a 100
b 200
Name: u, dtype: int64
如果我们想强制生成级别,我们可以使用 _align_series
中的分支来处理索引不相等的情况:
join_index, lidx, ridx = self.index.join( other.index, how=join, level=level, return_indexers=True ) left = self._reindex_indexer(join_index, lidx, copy) right = other._reindex_indexer(join_index, ridx, copy)
我们可以使用 Index.join
和 _reindex_indexer
来创建对齐系列:
join_index, lidx, ridx = s.index.join(
u.index, how='outer', level=None, return_indexers=True
)
left = s._reindex_indexer(join_index, lidx, copy=False)
right = u._reindex_indexer(join_index, ridx, copy=False)
*注意:我们正在使用私有方法,因为 public API.
中没有等效的重新索引器现在我们已经对齐系列了,我们可以这样做:
left + right
获取结果:
Common Level s Level u
Foo a a 101
b 201
b a 102
b 202
dtype: int64
如果我们想避免使用私有方法,我们也可以iloc
to select values using index locations then set_axis
用带有适当标签的连接索引覆盖:
join_index, lidx, ridx = s.index.join(
u.index, how='outer', level=None, return_indexers=True
)
left = s.iloc[lidx].set_axis(join_index)
right = u.iloc[ridx].set_axis(join_index)
left + right
Common Level s Level u
Foo a a 101
b 201
b a 102
b 202
dtype: int64