如何在每个列都有系列的DataFrame上进行操作
问题内容:
目标与动机
我已经多次看过这种问题,也看到过许多其他涉及到这一问题的问题。最近,我在寻找适当的规范问答时不得不花一些时间在评论中解释这个概念。我找不到一个,所以我想写一个。
这个问题通常是针对特定的运算出现的,但同样适用于大多数算术运算。
- 如何从a
Series
的每一列中减去aDataFrame
? - 如何
Series
从中的每一列添加aDataFrame
? - 如何
Series
从a的每一列乘以aDataFrame
? - 如何
Series
从a的每一列中划分aDataFrame
?
问题
给定Series
s
和DataFrame
df
。如何处理df
with的每一列s
?
df = pd.DataFrame(
[[1, 2, 3], [4, 5, 6]],
index=[0, 1],
columns=['a', 'b', 'c']
)
s = pd.Series([3, 14], index=[0, 1])
当我尝试添加它们时,我得到了所有 np.nan
df + s
a b c 0 1
0 NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN
我以为我应该得到的是
a b c
0 4 5 6
1 18 19 20
问题答案:
请承担序言。首先解决一些更高层次的概念很重要。由于我的动机是分享知识和授课,所以我想使这一点尽可能清晰。
它有利于建立一个什么样的心理模型Series
和DataFrame
对象。
解剖 Series
Series
应该将A视为增强型词典。这并不总是一个完美的类比,但是我们将从这里开始。另外,您还可以进行其他类比,但我将目标放在字典上,以证明本文的目的。
index
这些是我们可以参考以获取相应值的键。当索引的元素是唯一的时,与字典的比较变得非常接近。
values
这些是由索引键入的相应值。
解剖 DataFrame
一个DataFrame
应该被看作是一个字典Series
或Series
的Series
。在这种情况下,键是列名称,值是列本身作为Series
对象。每个人都Series
同意分享相同的内容index
,这是的索引DataFrame
。
columns
这些是我们可以参考以获取相应键的键Series
。
index
这是所有Series
值均同意共享的索引。
注意:RE:columns
和index
对象
它们是同一种东西。甲DataFrame
小号index
可以用作另一DataFrame
小号columns
。实际上,当您进行df.T
移调时会发生这种情况。
values
这是一个二维数组,其中包含数据DataFrame
。现实情况是,values
是 不是
有什么存储在里面DataFrame
的对象。(有时候是这样,但是我不想描述块管理器)。关键是,最好将其视为对数据二维数组的访问。
定义样本数据
这些样本pandas.Index
可以被用作对象index
的一个Series
或DataFrame
或可以用作所述columns
的一DataFrame
idx_lower = pd.Index([*'abcde'], name='lower')
idx_range = pd.RangeIndex(5, name='range')
这些是pandas.Series
使用上述pandas.Index
对象的示例对象
s0 = pd.Series(range(10, 15), idx_lower)
s1 = pd.Series(range(30, 40, 2), idx_lower)
s2 = pd.Series(range(50, 10, -8), idx_range)
这些是pandas.DataFrame
使用上述pandas.Index
对象的示例对象
df0 = pd.DataFrame(100, index=idx_range, columns=idx_lower)
df1 = pd.DataFrame(
np.arange(np.product(df0.shape)).reshape(df0.shape),
index=idx_range, columns=idx_lower
)
Series
上 Series
当在两个上操作时Series
,对齐是显而易见的。您将index
其中一个Series
与index
另一个对齐。
s1 + s0
lower
a 40
b 43
c 46
d 49
e 52
dtype: int64
这与我在操作前随机洗牌时的情况相同。索引仍将对齐。
s1 + s0.sample(frac=1)
lower
a 40
b 43
c 46
d 49
e 52
dtype: int64
而且是 不是
时候,而不是我与洗牌的值进行操作的情况Series
。在这种情况下,Pandas不需要index
与之对齐,因此只能从某个位置操作。
s1 + s0.sample(frac=1).values
lower
a 42
b 42
c 47
d 50
e 49
dtype: int64
添加标量
s1 + 1
lower
a 31
b 33
c 35
d 37
e 39
dtype: int64
DataFrame
上 DataFrame
在两个DataFrame
s之间进行操作时,类似情况也是如此
。对齐是显而易见的,并且执行了我们认为应该做的事情
df0 + df1
lower a b c d e
range
0 100 101 102 103 104
1 105 106 107 108 109
2 110 111 112 113 114
3 115 116 117 118 119
4 120 121 122 123 124
DataFrame
在两个轴上随机播放秒。在index
和columns
仍然对齐,给我们同样的事情。
df0 + df1.sample(frac=1).sample(frac=1, axis=1)
lower a b c d e
range
0 100 101 102 103 104
1 105 106 107 108 109
2 110 111 112 113 114
3 115 116 117 118 119
4 120 121 122 123 124
同样的改组,但添加数组而不是DataFrame
。不再对齐,将获得不同的结果。
df0 + df1.sample(frac=1).sample(frac=1, axis=1).values
lower a b c d e
range
0 123 124 121 122 120
1 118 119 116 117 115
2 108 109 106 107 105
3 103 104 101 102 100
4 113 114 111 112 110
添加一维数组。将与列对齐并跨行广播。
df0 + [*range(2, df0.shape[1] + 2)]
lower a b c d e
range
0 102 103 104 105 106
1 102 103 104 105 106
2 102 103 104 105 106
3 102 103 104 105 106
4 102 103 104 105 106
添加标量。没有什么可以与所有广播内容保持一致的
df0 + 1
lower a b c d e
range
0 101 101 101 101 101
1 101 101 101 101 101
2 101 101 101 101 101
3 101 101 101 101 101
4 101 101 101 101 101
DataFrame
上 Series
如果将DataFrame
s视为值的字典,Series
并将sSeries
视为值的字典,那么很自然的是,在aDataFrame
和之间进行操作时Series
,应按“键”对齐它们。
s0:
lower a b c d e
10 11 12 13 14
df0:
lower a b c d e
range
0 100 100 100 100 100
1 100 100 100 100 100
2 100 100 100 100 100
3 100 100 100 100 100
4 100 100 100 100 100
当我们进行操作时,10
ins0['a']
被添加到df0['a']
df0 + s0
lower a b c d e
range
0 110 111 112 113 114
1 110 111 112 113 114
2 110 111 112 113 114
3 110 111 112 113 114
4 110 111 112 113 114
问题的核心和帖子的重点
如果我要s2
和df0
怎么办?
s2: df0:
| lower a b c d e
range | range
0 50 | 0 100 100 100 100 100
1 42 | 1 100 100 100 100 100
2 34 | 2 100 100 100 100 100
3 26 | 3 100 100 100 100 100
4 18 | 4 100 100 100 100 100
当我手术时,我得到np.nan
了问题中所引用的一切
df0 + s2
a b c d e 0 1 2 3 4
range
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
这不会产生我们想要的。因为Pandas正在将index
ofs2
与columns
of对齐df0
。该columns
结果包含的工会index
的s2
及columns
的df0
。
我们可以通过棘手的换位来伪造它
(df0.T + s2).T
lower a b c d e
range
0 150 150 150 150 150
1 142 142 142 142 142
2 134 134 134 134 134
3 126 126 126 126 126
4 118 118 118 118 118
但是事实证明,熊猫有更好的解决方案。有一些操作方法可让我们传递axis
参数以指定要对齐的轴。
-
sub
+
add
*
mul
/
div
**
pow
所以答案很简单
df0.add(s2, axis='index')
lower a b c d e
range
0 150 150 150 150 150
1 142 142 142 142 142
2 134 134 134 134 134
3 126 126 126 126 126
4 118 118 118 118 118
原来axis='index'
是的同义词axis=0
。
由于是axis='columns'
同义axis=1
df0.add(s2, axis=0)
lower a b c d e
range
0 150 150 150 150 150
1 142 142 142 142 142
2 134 134 134 134 134
3 126 126 126 126 126
4 118 118 118 118 118
其余操作
df0.sub(s2, axis=0)
lower a b c d e
range
0 50 50 50 50 50
1 58 58 58 58 58
2 66 66 66 66 66
3 74 74 74 74 74
4 82 82 82 82 82
df0.mul(s2, axis=0)
lower a b c d e
range
0 5000 5000 5000 5000 5000
1 4200 4200 4200 4200 4200
2 3400 3400 3400 3400 3400
3 2600 2600 2600 2600 2600
4 1800 1800 1800 1800 1800
df0.div(s2, axis=0)
lower a b c d e
range
0 2.000000 2.000000 2.000000 2.000000 2.000000
1 2.380952 2.380952 2.380952 2.380952 2.380952
2 2.941176 2.941176 2.941176 2.941176 2.941176
3 3.846154 3.846154 3.846154 3.846154 3.846154
4 5.555556 5.555556 5.555556 5.555556 5.555556
df0.pow(1 / s2, axis=0)
lower a b c d e
range
0 1.096478 1.096478 1.096478 1.096478 1.096478
1 1.115884 1.115884 1.115884 1.115884 1.115884
2 1.145048 1.145048 1.145048 1.145048 1.145048
3 1.193777 1.193777 1.193777 1.193777 1.193777
4 1.291550 1.291550 1.291550 1.291550 1.291550