Pandas 文档中的“广播”一词是什么意思?
- 2025-03-04 08:24:00
- admin 原创
- 103
问题描述:
我正在阅读 Pandas 文档,术语“广播”被广泛使用,但从未真正定义或解释过。
这是什么意思?
解决方案 1:
因此,术语“广播”来自numpy,简单地说,它解释了在 n 维数组(可以是面板、数据框、系列)或标量值之间执行操作时产生的输出规则。
使用标量值进行广播
因此最简单的情况就是乘以标量值:
In [4]:
s = pd.Series(np.arange(5))
s
Out[4]:
0 0
1 1
2 2
3 3
4 4
dtype: int32
In [5]:
s * 10
Out[5]:
0 0
1 10
2 20
3 30
4 40
dtype: int32
我们用数据框得到了相同的预期结果:
In [6]:
df = pd.DataFrame({'a':np.random.randn(4), 'b':np.random.randn(4)})
df
Out[6]:
a b
0 0.216920 0.652193
1 0.968969 0.033369
2 0.637784 0.856836
3 -2.303556 0.426238
In [7]:
df * 10
Out[7]:
a b
0 2.169204 6.521925
1 9.689690 0.333695
2 6.377839 8.568362
3 -23.035557 4.262381
因此,从技术上讲,这里发生的情况是,标量值已经沿着上面的 Series 和 DataFrame 的相同维度进行广播。
使用一维数组进行广播
假设我们有一个形状为 4 x 3(4 行 x 3 列)的二维数据框,我们可以使用与行长相同的长度的一维系列沿 x 轴执行操作:
In [8]:
df = pd.DataFrame({'a':np.random.randn(4), 'b':np.random.randn(4), 'c':np.random.randn(4)})
df
Out[8]:
a b c
0 0.122073 -1.178127 -1.531254
1 0.011346 -0.747583 -1.967079
2 -0.019716 -0.235676 1.419547
3 0.215847 1.112350 0.659432
In [26]:
df.iloc[0]
Out[26]:
a 0.122073
b -1.178127
c -1.531254
Name: 0, dtype: float64
In [27]:
df + df.iloc[0]
Out[27]:
a b c
0 0.244146 -2.356254 -3.062507
1 0.133419 -1.925710 -3.498333
2 0.102357 -1.413803 -0.111707
3 0.337920 -0.065777 -0.871822
上面的内容一开始看起来很有趣,直到你明白发生了什么,我取了第一行值并将其按行添加到 df,可以使用这张图片进行可视化(来源于scipy
):
一般规则是这样的:
为了广播,操作中两个数组的尾轴的大小必须相同,或者其中一个必须为 1。
因此,如果我尝试添加一个长度不匹配的一维数组,比如说一个有 4 个元素的数组,这与 numpy 不同,后者会引发一个ValueError
,而在 Pandas 中,你会得到一个充满NaN
值的 df:
In [30]:
df + pd.Series(np.arange(4))
Out[30]:
a b c 0 1 2 3
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN
现在,pandas 的一些优点是它会尝试使用现有的列名和行标签进行对齐,这可能会妨碍尝试执行像这样的更花哨的广播:
In [55]:
df[['a']] + df.iloc[0]
Out[55]:
a b c
0 0.244146 NaN NaN
1 0.133419 NaN NaN
2 0.102357 NaN NaN
3 0.337920 NaN NaN
在上面,我使用双下标强制形状为 (4,1),但是我们在尝试使用第一行进行广播时看到一个问题,因为列对齐仅在第一列上对齐。为了获得与上图所示相同的广播形式,我们必须分解为 numpy 数组,然后将其变为匿名数据:
In [56]:
df[['a']].values + df.iloc[0].values
Out[56]:
array([[ 0.24414608, -1.05605392, -1.4091805 ],
[ 0.13341899, -1.166781 , -1.51990758],
[ 0.10235701, -1.19784299, -1.55096957],
[ 0.33792013, -0.96227987, -1.31540645]])
也可以在三维中进行广播,但我并不经常接触这些东西,但 numpy、scipy 和 pandas 书中有例子展示了它是如何工作的。
一般来说,要记住的是,除了简单的标量值之外,对于 nD 数组,短轴/尾轴长度必须匹配,或者其中一个必须为 1。
更新
看来上面的内容现在导致了ValueError: Unable to coerce to Series, length must be 1: given 3
最新版本的熊猫0.20.2
因此您必须.values
先拨打df
:
In[42]:
df[['a']].values + df.iloc[0].values
Out[42]:
array([[ 0.244146, -1.056054, -1.409181],
[ 0.133419, -1.166781, -1.519908],
[ 0.102357, -1.197843, -1.55097 ],
[ 0.33792 , -0.96228 , -1.315407]])
为了将其恢复为原始 df,我们可以从 np 数组构造一个 df,并将参数中的原始列传递给构造函数:
In[43]:
pd.DataFrame(df[['a']].values + df.iloc[0].values, columns=df.columns)
Out[43]:
a b c
0 0.244146 -1.056054 -1.409181
1 0.133419 -1.166781 -1.519908
2 0.102357 -1.197843 -1.550970
3 0.337920 -0.962280 -1.315407
解决方案 2:
使用 MultiIndex 在 Pandas DataFrames 上进行广播
DataFrame
对于带有 的 s来说,广播尤其有趣,pandas.MultiIndex
正如我在下面的例子中向您展示的那样。
Pandas 可以通过多维甚至分层索引在添加的维度上进行广播,如果您知道如何使用它,这将非常强大。您无需编写循环和条件。您可以依赖已经有效的方法。
我在 0 轴(索引)上填充了两个pandas.DataFrames
,af
并df
用一个pandas.MultiIndex
,以及 10 列标有整数的列,例如引用来自蒙特卡洛模拟的情景数据。
和pandas.MultiIndex
的 es在中有一些共同之处(我把它们称为维度)。并非所有(较新的 pandas 版本称它们为)都需要在匹配的维度中。在示例中,维度“a”和“c”是共享的。在两个框架中,“a”维度都有条目 ( ) [“A”和“B”],而在“c”维度中,框架和分别有条目和。af
`dflevels
nameslabels
codeslabels
afbf
[0, 1, 2, 3]`[0, 1, 2]
尽管如此,广播工作得很好。这意味着在下面的例子中,当将两个帧相乘时,将对匹配维度中具有匹配条目的每个组执行分组乘法。
下面的例子展示了乘法的广播,但它适用于pandas.DataFrames
左侧和右侧之间的所有二进制运算。
一些观察
请注意,两个框架都可以有额外的维度。一组名称不一定是另一组名称的子集。在示例中,我们分别['a', 'b', 'c']
对和['a', 'c', 'd']
框架有和af
`bf`
结果正如预期的那样覆盖了整个空间:['a', 'b', 'c', 'd']
由于维度 'c' 没有code
帧中的条目()'3' bf
,而af
有,因此结果用NaN
s 填充结果块。
请注意,此处使用的是 pandas 1.0.3。使用 pandas 0.23.4 版本时,无法使用具有多个重叠维度的广播。
同时在 0 轴和 1 轴上进行广播也有效。请参阅最后两个示例。例如,如果您只想将af
与 相乘bf[0].to_frame()
,则为第一种情况。但它只会应用于标签相同的列(正如广播的目的)。
更多提示
如果您想将af
框架与列向量相乘(有时我需要应用一些具有额外维度的权重),那么您可以轻松地自己实现它。您可以将数据框扩展为n = af.shape[1]
列,然后使用它进行乘法。看看numpy.tile
如何“不”编码就做到这一点。
>>> af
Values 0 1 2 3 4 5 6 7 8 9
a b c
A a 0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
1 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
2 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
3 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
b 0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
1 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
2 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
3 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
c 0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
1 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
2 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
3 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
B a 0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
1 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
2 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
3 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
b 0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
1 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
2 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
3 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
c 0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
1 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
2 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
3 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
>>> bf
Values 0 1 2 3 4 5 6 7 8 9
a c d
A 0 * 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0
# 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0
1 * 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0
# 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0
2 * 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0
# 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0
B 0 * 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0
# 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0
1 * 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0
# 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0
2 * 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0
# 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0
>>> af * bf
Values 0 1 2 3 4 5 6 7 8 9
a c b d
A 0 a * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
b * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
c * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
1 a * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
b * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
c * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
2 a * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
b * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
c * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
3 a NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
b NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
c NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
B 0 a * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
b * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
c * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
1 a * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
b * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
c * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
2 a * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
b * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
c * 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
# 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
3 a NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
b NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
c NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
>>> af * bf[0] # Raises Error: ValueError: cannot join with no overlapping index names
# Removed that part
>>> af * bf[0].to_frame() # works consistently
0 1 2 3 4 5 6 7 8 9
a c b d
A 0 a * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
b * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
c * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 a * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
b * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
c * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 a * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
b * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
c * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 a NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
b NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
c NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
B 0 a * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
b * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
c * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 a * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
b * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
c * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 a * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
b * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
c * 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
# 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 a NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
b NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
c NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
>>> cf = bf[0].to_frame()
>>> cf.columns = [3]
>>> af * cf # And as expected we can broadcast over the same column labels at the same time
0 1 2 3 4 5 6 7 8 9
a c b d
A 0 a * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
b * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
c * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
1 a * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
b * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
c * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
2 a * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
b * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
c * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
3 a NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
b NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
c NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
B 0 a * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
b * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
c * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
1 a * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
b * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
c * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
2 a * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
b * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
c * NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
# NaN NaN NaN 6.0 NaN NaN NaN NaN NaN NaN
3 a NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
b NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
c NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
扫码咨询,免费领取项目管理大礼包!