Je dois ajouter une nouvelle colonne ("delta") à un dataframe en calculant la différence entre chaque valeur de ligne dans la colonne "value" et la valeur dans la même colonne quand num = 5, avec la même couleur et pour chaque grouper. Le résultat devrait être le suivant:
import plotly.graph_objs as go
import pandas as pd
d = {
"group" : ["Group1", "Group1", "Group1", "Group1", "Group1", "Group1", "Group1", "Group1", "Group1", "Group1", "Group1", "Group1", "Group2", "Group2", "Group2", "Group2", "Group2", "Group2", "Group2", "Group2","Group2", "Group2", "Group2", "Group2"],
"color" : ["red", "green", "blue", "yellow", "red", "green", "blue", "yellow", "red", "green", "blue", "yellow", "red", "green", "blue", "yellow", "red", "green", "blue", "yellow", "red", "green", "blue", "yellow"],
"num" : [1, 1, 1, 1, 5, 5, 5, 5, 7, 7, 7, 7, 1, 1, 1, 1, 5, 5, 5, 5, 7, 7, 7, 7],
"value" : [0.1, 0.2, 0.3, 0.6, 0.5, 0.6, 0.7, 0.5, 0.8, 0.9, 0.7, 0.6, 0.1, 0.2, 0.3, 0.6, 0.5, 0.6, 0.7, 0.5, 0.8, 0.9, 0.7, 0.6,]
}
df = pd.DataFrame(d)
df_pivot = pd.pivot_table(df, values = ["value"], index = ["group", "color", "num"])
df_pivot["delta"] = df_pivot["value"] # what/how should I substract !?
print(df_pivot)
J'ai essayé d'utiliser pivot_table, je suppose que c'est un début, mais je ne vois vraiment pas comment faire ce calcul conditionnel.
Avez-vous une idée de la manière dont cela pourrait être fait?
Code actuel:
group color num value delta Group1 red 1 0.1 -0.4 (0.1 - 0.5 (0.5 is the value in Group1, color=red and num=5)) Group1 green 1 0.2 -0.4 (0.2 - 0.6 (0.6 is the value in Group1, color=green and num=5)) Group1 blue 1 0.3 -0.4 (0.3 - 0.7) Group1 yellow 1 0.6 0.1 (0.6 - 0.5) Group1 red 5 0.5 0 Group1 green 5 0.6 0 Group1 blue 5 0.7 0 Group1 yellow 5 0.5 0 Group1 red 7 0.8 0.3 Group1 green 7 0.9 0.3 Group1 blue 7 0.7 0 Group1 yellow 7 0.6 0.1 Group2 red 1 0.1 etc.
3 Réponses :
Comme ceci:
In [1771]: m = df[df.num.eq(5)]
In [1774]: res = pd.merge(df,m, on=['group', 'color'])
In [1779]: res['delta'] = res['value_x'] - res['value_y']
In [1781]: res = res.drop(['num_y', 'value_y'],1).rename(columns={'num_x': 'num', 'value_x': 'value'})
In [1782]: res
Out[1782]:
group color num value delta
0 Group1 red 1 0.1 -0.4
1 Group1 red 5 0.5 0.0
2 Group1 red 7 0.8 0.3
3 Group1 green 1 0.2 -0.4
4 Group1 green 5 0.6 0.0
5 Group1 green 7 0.9 0.3
6 Group1 blue 1 0.3 -0.4
7 Group1 blue 5 0.7 0.0
8 Group1 blue 7 0.7 0.0
9 Group1 yellow 1 0.6 0.1
10 Group1 yellow 5 0.5 0.0
11 Group1 yellow 7 0.6 0.1
@Yas Cette solution serait robuste. Prendra soin de tous les cas correctement.
Votre réponse était la première et elle est facile à comprendre. Mais je n'aime pas le drop et le renommer à la fin;)
pd.merge ajoute _x et _y dans les noms de colonnes qu'il trouve en double dans les dataframes. Par conséquent, je laisse tomber et renommez. Pas moyen de s'en sortir.
Oui j'ai compris ça, je trouve la réponse d'Andy L. avec où et transformer plus concise.
Génial. C'est votre question et vous avez le droit de choisir la meilleure réponse pour vous-même.
créez un dict (groupe, couleur) et mappez-le à chaque ligne.
df['delta'] = (
df.apply(lambda x: x.value -
df.loc[(df.group==x.group) & (df.color==x.color) & (df.num==5)].iloc[0].value,
axis=1)
)
ou
d = (
df.groupby(['group','color'])
.apply(lambda x: x.loc[x.num.eq(5)].head(1)).value
.reset_index(2,drop=True)
.to_dict()
)
df['delta'] = (
df.apply(lambda x: x.value - d.get((x.group,x.color), x.value), axis=1)
)
Oh, celui-ci fonctionne aussi. Je ne sais pas encore quel serait le meilleur à utiliser ...
Ma première solution devrait être plus robuste qui gère les cas où il n'y a pas d'autre ligne avec la même couleur et le numéro 5 dans le même groupe.
Utilisez where et transform
df['delta'] = (df.value -
df.where(df.num.eq(5)).groupby([df.group,df.color])
.value.transform('first'))
Out[16]:
group color num value delta
0 Group1 red 1 0.1 -0.4
1 Group1 green 1 0.2 -0.4
2 Group1 blue 1 0.3 -0.4
3 Group1 yellow 1 0.6 0.1
4 Group1 red 5 0.5 0.0
5 Group1 green 5 0.6 0.0
6 Group1 blue 5 0.7 0.0
7 Group1 yellow 5 0.5 0.0
8 Group1 red 7 0.8 0.3
9 Group1 green 7 0.9 0.3
10 Group1 blue 7 0.7 0.0
11 Group1 yellow 7 0.6 0.1
12 Group2 red 1 0.1 -0.4
13 Group2 green 1 0.2 -0.4
14 Group2 blue 1 0.3 -0.4
15 Group2 yellow 1 0.6 0.1
16 Group2 red 5 0.5 0.0
17 Group2 green 5 0.6 0.0
18 Group2 blue 5 0.7 0.0
19 Group2 yellow 5 0.5 0.0
20 Group2 red 7 0.8 0.3
21 Group2 green 7 0.9 0.3
22 Group2 blue 7 0.7 0.0
23 Group2 yellow 7 0.6 0.1
J'aime vraiment celui-ci, j'essaie juste de comprendre la partie après groupby (value.transform ('first')).
@Yas: il sélectionne le premier non-NaN de valeur de chaque couleur de groupe et remplit cette valeur à l'ensemble du groupe. La commande après le signe moins peut également devenir df.value.where (df.num.eq (5)). Groupby ([df.group, df.color]). Tr ansform ('first') < / code>
pouvez-vous s'il vous plaît ajouter la sortie souhaitée
Je l'ai fait dans la première partie de la question
essayez avec
df ['dealta'] = df ['value'] -0,5;print (df)pas besoin de faire pivoter ce que vous attendiez?ce n'est pas une constante c'est vraiment une valeur variable en fonction de la condition