Pandas数据框与系列相乘

51
什么是将Pandas DataFrame的所有列乘以存储在Series中的列向量的最佳方法?我曾经在Matlab中使用repmat()来完成这个任务,但在Pandas中它不存在。我可以使用np.tile(),但每次转换数据结构看起来很难看。谢谢。
3个回答

79

5
我之前不知道DataFrame.mul这个函数!使用它会更加简单。 - spencerlyon2
2
对我没用。我得到了:TypeError: can't multiply sequence by non-int of type 'float' - James Hirschorn

12

使用 DataFrame 方法 apply 可以轻松实现这一点。

In[1]: import pandas as pd; import numpy as np

In[2]: df = pd.DataFrame(np.arange(40.).reshape((8, 5)), columns=list('abcde')); df
Out[2]: 
        a   b   c   d   e
    0   0   1   2   3   4
    1   5   6   7   8   9
    2  10  11  12  13  14
    3  15  16  17  18  19
    4  20  21  22  23  24
    5  25  26  27  28  29
    6  30  31  32  33  34
    7  35  36  37  38  39

In[3]: ser = pd.Series(np.arange(8) * 10); ser
Out[3]: 
    0     0
    1    10
    2    20
    3    30
    4    40
    5    50
    6    60
    7    70

现在我们有了自己的DataFrameSeries,需要一个函数传递给apply
In[4]: func = lambda x: np.asarray(x) * np.asarray(ser)

我们可以将这个传递给 df.apply,然后就可以了。
In[5]: df.apply(func)
Out[5]:
          a     b     c     d     e
    0     0     0     0     0     0
    1    50    60    70    80    90
    2   200   220   240   260   280
    3   450   480   510   540   570
    4   800   840   880   920   960
    5  1250  1300  1350  1400  1450
    6  1800  1860  1920  1980  2040
    7  2450  2520  2590  2660  2730

df.apply 默认以列为单位进行操作,但是也可以通过将参数 axis=1 传递给 apply 来按行执行操作。

In[6]: ser2 = pd.Series(np.arange(5) *5); ser2
Out[6]: 
    0     0
    1     5
    2    10
    3    15
    4    20

In[7]: func2 = lambda x: np.asarray(x) * np.asarray(ser2)

In[8]: df.apply(func2, axis=1)
Out[8]: 
       a    b    c    d    e
    0  0    5   20   45   80
    1  0   30   70  120  180
    2  0   55  120  195  280
    3  0   80  170  270  380
    4  0  105  220  345  480
    5  0  130  270  420  580
    6  0  155  320  495  680
    7  0  180  370  570  780

这可以通过在apply内部定义匿名函数来更加简洁地完成。
In[9]: df.apply(lambda x: np.asarray(x) * np.asarray(ser))
Out[9]: 
          a     b     c     d     e
    0     0     0     0     0     0
    1    50    60    70    80    90
    2   200   220   240   260   280
    3   450   480   510   540   570
    4   800   840   880   920   960
    5  1250  1300  1350  1400  1450
    6  1800  1860  1920  1980  2040
    7  2450  2520  2590  2660  2730

In[10]: df.apply(lambda x: np.asarray(x) * np.asarray(ser2), axis=1)
Out[10]:
       a    b    c    d    e
    0  0    5   20   45   80
    1  0   30   70  120  180
    2  0   55  120  195  280
    3  0   80  170  270  380
    4  0  105  220  345  480
    5  0  130  270  420  580
    6  0  155  320  495  680
    7  0  180  370  570  780

1
为什么不创建自己的数据框瓦片函数呢?
def tile_df(df, n, m):
    dfn = df.T
    for _ in range(1, m):
        dfn = dfn.append(df.T, ignore_index=True)
    dfm = dfn.T
    for _ in range(1, n):
        dfm = dfm.append(dfn.T, ignore_index=True)
    return dfm

例子:

df = pandas.DataFrame([[1,2],[3,4]])
tile_df(df, 2, 3)
#    0  1  2  3  4  5
# 0  1  2  1  2  1  2
# 1  3  4  3  4  3  4
# 2  1  2  1  2  1  2
# 3  3  4  3  4  3  4

然而,docs中指出:“DataFrame不打算成为ndarray的替代品,因为它的索引语义在某些地方与矩阵有很大的不同。”这可能应该被解释为“如果你要做大量的矩阵操作,请使用numpy”

谢谢你的回答。但是我需要逐元素相乘。在Matlab中,这可能是df .* repmat(s, 1, 2)。也许最好的方法是将数据框转换为ndarray。 - jianpan
@jianpan 我明白了,我不理解repmat/tile... 我想建议你只使用numpy? - Andy Hayden
@jianpan 这个自定义瓷砖函数怎么样? - Andy Hayden
谢谢Hayden。我在这里犹豫是否将df转换为ndarray,因为在逐元素相乘后,我需要将数据返回到df进行其他计算。我认为这可能是Pandas中存在的一些东西,因为按列缩放在金融应用程序中是非常常见的操作。 - jianpan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接