J'essaie de multiplier deux colonnes existantes dans un pandas Dataframe (orders_df) - Prix (prix de clôture) et Amount (quantités en stock), puis d'ajouter le calcul à une nouvelle colonne appelée "Valeur". Pour une raison quelconque, lorsque j'exécute ce code, toutes les lignes de la colonne "Valeur" sont des nombres positifs, tandis que certaines d'entre elles doivent être négatives. Sous la colonne Action du DataFrame, il y a sept lignes avec la chaîne "Vendre" et sept avec la chaîne "Acheter".
for i in orders_df.Action:
if i == 'Sell':
orders_df['Value'] = orders_df.Prices*orders_df.Amount
Elif i == 'Buy':
orders_df['Value'] = -orders_df.Prices*orders_df.Amount)
S'il vous plaît laissez-moi savoir ce que je fais mal!
Si nous sommes prêts à sacrifier le caractère succinct de la solution de Hayden, on pourrait également faire quelque chose comme ceci:
In [22]: orders_df['C'] = orders_df.Action.apply(
lambda x: (1 if x == 'Sell' else -1))
In [23]: orders_df # New column C represents the sign of the transaction
Out[23]:
Prices Amount Action C
0 3 57 Sell 1
1 89 42 Sell 1
2 45 70 Buy -1
3 6 43 Sell 1
4 60 47 Sell 1
5 19 16 Buy -1
6 56 89 Sell 1
7 3 28 Buy -1
8 56 69 Sell 1
9 90 49 Buy -1
Nous avons maintenant éliminé la nécessité de la déclaration if
. En utilisant DataFrame.apply()
, nous supprimons également la boucle for
. Comme Hayden l'a noté, les opérations vectorisées sont toujours plus rapides.
In [24]: orders_df['Value'] = orders_df.Prices * orders_df.Amount * orders_df.C
In [25]: orders_df # The resulting dataframe
Out[25]:
Prices Amount Action C Value
0 3 57 Sell 1 171
1 89 42 Sell 1 3738
2 45 70 Buy -1 -3150
3 6 43 Sell 1 258
4 60 47 Sell 1 2820
5 19 16 Buy -1 -304
6 56 89 Sell 1 4984
7 3 28 Buy -1 -84
8 56 69 Sell 1 3864
9 90 49 Buy -1 -4410
Cette solution prend deux lignes de code au lieu d'une, mais est un peu plus facile à lire. Je soupçonne que les coûts de calcul sont similaires.
Je pense qu'une solution élégante consiste à utiliser la méthode where
(voir également le API docs
):
In [37]: values = df.Prices * df.Amount
In [38]: df['Values'] = values.where(df.Action == 'Sell', other=-values)
In [39]: df
Out[39]:
Prices Amount Action Values
0 3 57 Sell 171
1 89 42 Sell 3738
2 45 70 Buy -3150
3 6 43 Sell 258
4 60 47 Sell 2820
5 19 16 Buy -304
6 56 89 Sell 4984
7 3 28 Buy -84
8 56 69 Sell 3864
9 90 49 Buy -4410
De plus, cela devrait être la solution la plus rapide.
Vous pouvez utiliser la méthode DataFrame apply
:
order_df['Value'] = order_df.apply(lambda row: (row['Prices']*row['Amount']
if row['Action']=='Sell'
else -row['Prices']*row['Amount']),
axis=1)
Il est généralement plus rapide d’utiliser ces méthodes plutôt que d’en finir pour les boucles.
Depuis que cette question a été posée à nouveau, je pense qu'une bonne approche consiste à utiliser assign .
Le code est assez expressif et auto-descriptif:
df = df.assign(Value = lambda x: x.Prices * x.Amount * x.Action.replace({'Buy' : 1, 'Sell' : -1}))
Pour moi, c'est le plus clair et le plus intuitif:
values = []
for action in ['Sell','Buy']:
amounts = orders_df['Amounts'][orders_df['Action'==action]].values
if action == 'Sell':
prices = orders_df['Prices'][orders_df['Action'==action]].values
else:
prices = -1*orders_df['Prices'][orders_df['Action'==action]].values
values += list(amounts*prices)
orders_df['Values'] = values
La méthode .values
renvoie un numpy array
qui vous permet de multiplier facilement les éléments. Vous pouvez ensuite générer de manière cumulative une liste en "ajoutant".
Bonne solution de bmu. Je pense qu'il est plus facile de mettre les valeurs entre parenthèses et extérieures.
df['Values'] = np.where(df.Action == 'Sell',
df.Prices*df.Amount,
-df.Prices*df.Amount)
Utilisation de quelques pandas intégrés dans des fonctions.
df['Values'] = np.where(df.Action.eq('Sell'),
df.Prices.mul(df.Amount),
-df.Prices.mul(df.Amount))