pandas dataframe multiplier par une série

Quelle est la meilleure façon de multiplier toutes les colonnes D'un Pandas DataFrame par un vecteur colonne stockées dans un Series? J'ai utilisé pour ce faire dans Matlab avec repmat(), qui n'existe pas dans les Pandas. Je peux utiliser np.tile(), mais il semble laid pour convertir la structure de données d'avant en arrière à chaque fois.

Merci.

23
demandé sur tmthydvnprt 2012-11-01 00:20:44

3 réponses

Qu'est-ce qui ne va pas avec

result = dataframe.mul(series, axis=0)

?

http://pandas.pydata.org/pandas-docs/stable/basics.html#flexible-binary-operations

38
répondu Wes McKinney 2012-11-09 21:01:11

cela peut être accompli tout simplement avec la méthode 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

Maintenant que nous avons notre DataFrame et Series nous avons besoin d'une fonction pour passer à apply.

In[4]: func = lambda x: np.asarray(x) * np.asarray(ser)

Nous pouvons la transmettre à df.apply et nous êtes bon pour aller

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 agit par colonne par défaut, mais il peut aussi agir par ligne en passant axis=1 comme argument pour 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

cela pourrait être fait de façon plus concise en définition de la fonction anonyme à l'intérieur de 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
10
répondu spencerlyon2 2012-11-04 06:52:40

pourquoi ne pas créer votre propre fonction de tuile de dataframe:

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

Exemple:

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

Toutefois, le docs remarque: "DataFrame n'est pas destiné à remplacer le ndarray car sa sémantique d'indexation est très différente par endroits d'une matrice." ce qui devrait probablement être interprété comme "utiliser numpy si vous faites beaucoup de la matrice des trucs".

1
répondu Andy Hayden 2012-11-01 21:18:53