如何对每列的系列操作DataFrame

piR*_*red 41 python pandas

目标和动机

我已经多次看过这样的问题了,并且已经看到许多其他涉及这个问题的问题.最近,我不得不花时间在评论中解释这个概念,同时寻找合适的规范问答.我没找到一个,所以我以为我会写一个.

这个问题通常出现在特定的操作中,但同样适用于大多数算术运算.

  • 如何从a中Series的每一列中减去a DataFrame
  • 如何Series从a中的每一列添加DataFrame
  • 如何将a中Series的每一列乘以DataFrame
  • 如何Series从a中的每一列中划分a DataFrame

问题

鉴于Series sDataFrame df.如何在每列运行dfs

df = pd.DataFrame(
    [[1, 2, 3], [4, 5, 6]],
    index=[0, 1],
    columns=['a', 'b', 'c']
)

s = pd.Series([3, 14], index=[0, 1])
Run Code Online (Sandbox Code Playgroud)

当我尝试添加它们时,我得到了所有 np.nan

df + s

    a   b   c   0   1
0 NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN
Run Code Online (Sandbox Code Playgroud)

我认为我应该得到的是

    a   b   c
0   4   5   6
1  18  19  20
Run Code Online (Sandbox Code Playgroud)

piR*_*red 43

请承担序言.首先解决一些更高层次的概念很重要.由于我的动机是分享知识和教学,我想尽可能清楚地说明这一点.


创建关于什么SeriesDataFrame对象的心理模型是有帮助的.

解剖学 Series

A Series应该被认为是增强的字典.这并不总是一个完美的类比,但我们将从这里开始.此外,还有其他类比,你可以做,但我的目标是字典,以证明这篇文章的目的.

index

这些是我们可以引用以获取相应值的键.当索引的元素是唯一的时,与字典的比较变得非常接近.

values

这些是索引键入的相应值.

解剖学 DataFrame

一个DataFrame应该被看作是一个字典SeriesSeriesSeries.在这种情况下,键是列名称,值是列本身作为Series对象.每个人都Series同意分享相同index的内容DataFrame.

columns

这些是我们可以参考的关键字Series.

index

这是所有Series值同意共享的索引.

注意:RE:columnsindex对象

他们是同一种东西.甲DataFrame小号index可以用作另一DataFrame小号columns.事实上,当您进行df.T转置时会发生这种情况.

values

这是一个包含a中数据的二维数组DataFrame.现实情况是,values不是有什么存储在里面DataFrame的对象.(有时它是,但我不打算尝试描述块管理器).关键是,最好将其视为对数据的二维数组的访问.


定义样本数据

这些样本pandas.Index可以被用作对象indexSeriesDataFrame或可以用作所述columns的一DataFrame

idx_lower = pd.Index([*'abcde'], name='lower')
idx_range = pd.RangeIndex(5, name='range')
Run Code Online (Sandbox Code Playgroud)

这些是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)
Run Code Online (Sandbox Code Playgroud)

这些是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
)
Run Code Online (Sandbox Code Playgroud)

SeriesSeries

在两个操作时Series,对齐是显而易见的.你将index一个Seriesindex另一个对齐.

s1 + s0

lower
a    40
b    43
c    46
d    49
e    52
dtype: int64
Run Code Online (Sandbox Code Playgroud)

这与我在操作之前随机洗牌时的情况相同.指数仍将保持一致.

s1 + s0.sample(frac=1)

lower
a    40
b    43
c    46
d    49
e    52
dtype: int64
Run Code Online (Sandbox Code Playgroud)

而且是不是时候,而不是我与洗牌的值进行操作的情况Series.在这种情况下,熊猫没有index与之对齐,因此从一个位置开始运作.

s1 + s0.sample(frac=1).values

lower
a    42
b    42
c    47
d    50
e    49
dtype: int64
Run Code Online (Sandbox Code Playgroud)

添加标量

s1 + 1

lower
a    31
b    33
c    35
d    37
e    39
dtype: int64
Run Code Online (Sandbox Code Playgroud)

DataFrameDataFrame

在两个DataFrames 之间操作时也是如此
.对齐很明显,我们认为它应该做什么

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
Run Code Online (Sandbox Code Playgroud)

DataFrame在两个轴上随机播放.在indexcolumns仍然对齐,给我们同样的事情.

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
Run Code Online (Sandbox Code Playgroud)

同样的改组,但添加数组而不是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
Run Code Online (Sandbox Code Playgroud)

添加1维数组.将与列对齐并跨行广播.

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
Run Code Online (Sandbox Code Playgroud)

添加标量.什么都没有与所有广播一致

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
Run Code Online (Sandbox Code Playgroud)

DataFrameSeries

如果DataFrames是作为词典的词典SeriesSeries被认为是值的词典,那么当它们在a之间操作DataFrame并且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
Run Code Online (Sandbox Code Playgroud)

当我们操作时,10in s0['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
Run Code Online (Sandbox Code Playgroud)

问题的核心和帖子的重点

怎么样,如果我想s2df0

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
Run Code Online (Sandbox Code Playgroud)

当我操作时,我得到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
Run Code Online (Sandbox Code Playgroud)

这不会产生我们想要的东西.因为熊猫是对准indexs2columnsdf0.该columns结果包含的工会indexs2columnsdf0.

我们可以用棘手的换位来伪装它

(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
Run Code Online (Sandbox Code Playgroud)

但事实证明,熊猫有更好的解决方案.有一些操作方法允许我们传递一个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
Run Code Online (Sandbox Code Playgroud)

原来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
Run Code Online (Sandbox Code Playgroud)

其余的操作

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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

  • 对我来说,这是另一个很好的资源,可以为将来的问题标记 dup。:-) (3认同)

Ale*_*der 10

我更喜欢@piSquared提到的方法(即df.add(s,axis = 0)),但另一种方法applylambda数据帧中的每一列一起使用以执行操作:

>>>> df.apply(lambda col: col + s)
    a   b   c
0   4   5   6
1  18  19  20
Run Code Online (Sandbox Code Playgroud)

要将lambda函数应用于行,请使用axis=1:

>>> df.T.apply(lambda row: row + s, axis=1)
   0   1
a  4  18
b  5  19
c  6  20
Run Code Online (Sandbox Code Playgroud)

当转换更复杂时,此方法可能很有用,例如:

df.apply(lambda col: 0.5 * col ** 2 + 2 * s - 3)
Run Code Online (Sandbox Code Playgroud)