web-dev-qa-db-fra.com

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 de colonne stocké dans un Series? J'avais l'habitude de le faire dans Matlab avec repmat(), qui n'existe pas dans Pandas. Je peux utiliser np.tile(), mais ça a l'air moche de convertir la structure de données d'avant en arrière à chaque fois.

Merci.

30
jianpan
47
Wes McKinney

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 nos 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 transmettre ceci à df.apply et nous sommes prêts à partir

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 également 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 manière plus concise en définissant la fonction anonyme dans 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
spencerlyon2

Pourquoi ne pas créer votre propre fonction de mosaïque de trame de données:

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

Cependant , la note docs : "DataFrame n'est pas destinée à remplacer directement ndarray comme sa sémantique d'indexation est assez différente à certains endroits d'une matrice. " Ce qui devrait probablement être interprété comme " utilisez numpy si vous faites beaucoup de matrices de matrices ".

1
Andy Hayden