如何在每个列都有一个Series的DataFrame上进行操作

时间:2018-11-08 23:17:10

标签: python pandas

客观动机

我已经多次看到这种问题,也看到了许多其他涉及到这个问题的问题。最近,在寻找适当的规范问答时,我不得不花一些时间在评论中解释这个概念。我没有找到一个,所以我想写一个。

这个问题通常是针对特定的运算,但是同样适用于大多数算术运算。

  • 如何从Series的每一列中减去DataFrame
  • 如何从Series的每一列中添加DataFrame
  • 如何从Series的每一列中乘以DataFrame
  • 如何从Series的每一列中划分一个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])

当我尝试添加它们时,我得到了所有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

3 个答案:

答案 0 :(得分:37)

请承担序言。首先解决一些更高层次的概念很重要。由于我的动机是分享知识和授课,所以我想使这一点尽可能清晰。


创建一个SeriesDataFrame对象是什么的心理模型很有帮助。

Series

的剖析

Series应该被认为是增强型字典。这并不总是一个完美的类比,但是我们将从这里开始。另外,您还可以进行其他类比,但我将目标放在字典上,以证明本文的目的。

index

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

values

这些是由索引键键入的相应值。

DataFrame

的剖析

应将DataFrame视为Series的字典或Series的{​​{1}}。在这种情况下,键是列名,值是作为Series对象的列本身。每个Series同意共享相同的Series,即index的索引。

DataFrame

这些是我们可以参考以在相应的columns上获得的键。

Series

这是所有index值都同意共享的索引。

注意:RE:Seriescolumns对象

它们是同一种东西。 indexDataFrame可以用作另一个indexDataFrame。实际上,当您进行columns进行移调时,就会发生这种情况。

df.T

这是一个二维数组,其中包含values中的数据。现实情况是DataFrame 不是存储在values对象内部的内容。 (有时候是这样,但是我不想描述块管理器)。关键是,最好将其视为对数据的二维数组的访问。


定义样本数据

这些是示例DataFrame对象,可以用作pandas.Indexindex的{​​{1}}或可以用作{ {1}}

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) on 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 ) 的{​​{1}}与另一个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 on Series

在两个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 DataFrameDataFrame仍将对齐并给我们同样的东西。

DataFrame

相同的改组,但添加数组而不是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 on 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 视为值的字典,那么在{{ 1}}和DataFrame,它们应该按其“键”对齐。

Series

操作时,DataFrame中的Series被添加到Series的整个列中

DataFrame

问题的重点和帖子的重点

我要Seriess0: 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

操作时,我得到问题中引用的所有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 的{​​{1}}与s2的{​​{1}}对齐。结果的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 的{​​{1}}和np.nan的{​​{1}}的并集。

我们可以通过棘手的换位来伪造它

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

但是事实证明,熊猫有更好的解决方案。有一些操作方法可以让我们传递一个index参数来指定要对齐的轴。

s2 sub
columns add
df0 mul
columns div
index pow

所以答案很简单

s2

结果证明columnsdf0是同义词。
(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

-

其余操作

+

*

/

**

答案 1 :(得分: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

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

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

当转换更为复杂时,例如:

df.apply(lambda col: 0.5 * col ** 2 + 2 * s - 3)

答案 2 :(得分:0)

只是根据我自己的经验添加一个额外的层。它扩展了其他人在这里所做的工作。这显示了如何对带有 yashSeries 进行操作,该 DataFrame 具有要为其保留值的额外列。下面是该过程的简短演示。

import pandas as pd

d = [1.056323, 0.126681, 
     0.142588, 0.254143,
     0.15561, 0.139571,
     0.102893, 0.052411]
     
df = pd.Series(d, index = ['const', '426', '428', '424', '425', '423', '427', '636'])

print(df)
const    1.056323
426      0.126681
428      0.142588
424      0.254143
425      0.155610
423      0.139571
427      0.102893
636      0.052411

d2 = {
'loc': ['D', 'D', 'E', 'E', 'F', 'F', 'G', 'G', 'E', 'D'],
'426': [9, 2, 3, 2, 4, 0, 2, 7, 2, 8],
'428': [2, 4, 1, 0, 2, 1, 3, 0, 7, 8],
'424': [1, 10, 5, 8, 2, 7, 10, 0, 3, 5],
'425': [9, 2, 6, 8, 9, 1, 7, 3, 8, 6],
'423': [4, 2, 8, 7, 9, 6, 10, 5, 9, 9],
'423': [2, 7, 3, 10, 8, 1, 2, 9, 3, 9],
'427': [4, 10, 4, 0, 8, 3, 1, 5, 7, 7],
'636': [10, 5, 6, 4, 0, 5, 1, 1, 4, 8],
'seq': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
}

df2 = pd.DataFrame(d2)

print(df2)
  loc  426  428  424  425  423  427  636  seq
0   D    9    2    1    9    2    4   10    1
1   D    2    4   10    2    7   10    5    1
2   E    3    1    5    6    3    4    6    1
3   E    2    0    8    8   10    0    4    1
4   F    4    2    2    9    8    8    0    1
5   F    0    1    7    1    1    3    5    1
6   G    2    3   10    7    2    1    1    1
7   G    7    0    0    3    9    5    1    1
8   E    2    7    3    8    3    7    4    1
9   D    8    8    5    6    9    7    8    1

DataFrame 乘以 Series 并保留不同的列

  1. 创建您要操作的 DataFrameSeries 中元素的列表:
col = ['426', '428', '424', '425', '423', '427', '636']
  1. 使用列表执行您的操作并指明要使用的轴:
df2[col] = df2[col].mul(df[col], axis=1)

print(df2)
  loc       426       428       424      425       423       427       636  seq
0   D  1.140129  0.285176  0.254143  1.40049  0.279142  0.411572  0.524110    1
1   D  0.253362  0.570352  2.541430  0.31122  0.976997  1.028930  0.262055    1
2   E  0.380043  0.142588  1.270715  0.93366  0.418713  0.411572  0.314466    1
3   E  0.253362  0.000000  2.033144  1.24488  1.395710  0.000000  0.209644    1
4   F  0.506724  0.285176  0.508286  1.40049  1.116568  0.823144  0.000000    1
5   F  0.000000  0.142588  1.779001  0.15561  0.139571  0.308679  0.262055    1
6   G  0.253362  0.427764  2.541430  1.08927  0.279142  0.102893  0.052411    1
7   G  0.886767  0.000000  0.000000  0.46683  1.256139  0.514465  0.052411    1
8   E  0.253362  0.998116  0.762429  1.24488  0.418713  0.720251  0.209644    1
9   D  1.013448  1.140704  1.270715  0.93366  1.256139  0.720251  0.419288    1