1
votes

Impossible de supprimer des lignes avec une liste vide tout en prenant la moyenne des autres listes

J'ai une série chronologique df qui comporte 2 colonnes. J'essaie de supprimer toutes les listes vides des colonnes annual_cost tout en prenant une moyenne des listes contenant des flottants pour créer une valeur singulière pour chaque jour individuel. Il y a plusieurs valeurs pour la même date dans la colonne date et j'essaie donc de fusionner toutes les lignes en fonction de la date. df ressemble à ceci:

date        yearly_cost
0   2009-01-01  435.05
1   2009-01-02  366.11
2   2009-01-03  327.408

Certains jours auront plusieurs listes et donc je dois prendre une moyenne sur les deux listes pour créer une seule valeur.

J'ai essayé d'utiliser .dropna () , np.nanmean () et de faire la moyenne des listes avec ts.yearly_cost = [np.mean (i ) if isinstance (i, list) else i for i in ts.yearly_cost] avec concaténation par date avec .set_index ('date'). mean (axis = 1) .reset_index (name = 'Yearly_Cost') qui a travaillé pour des séries chronologiques dans le passé sans listes vides.

Je souhaite que le résultat final se présente comme tel:

    date        yearly_cost
0   2009-01-01  []
1   2009-01-02  [409.45,294.33,394.56]
2   2009-01-03  [403.45,175.30,323.67]
3   2009-01-01  [456.34,355.3,493.5]
4   2009-01-02  []
5   2009-01-03  [295.39, 439.23]

Toute aide à ce sujet serait grandement appréciée. Merci


1 commentaires

quelques questions: pourquoi vos coûts annuels sont-ils associés aux jours? pourquoi stockez-vous des listes dans des éléments de bloc de données? dataframe fonctionne beaucoup mieux avec des scalaires dans chaque ligne / colonne


3 Réponses :


4
votes

S'il y a des listes dans la colonne annual_cost , aplatissez-les d'abord, puis agrégez mean:

s = pd.DataFrame(df['yearly_cost'].values.tolist(), index=df['date']).stack()
df = s.mean(level=0).reset_index(name='yearly_cost')
print (df)
         date  yearly_cost
0  2009-01-02   366.113333
1  2009-01-03   327.408000
2  2009-01-01   435.046667

Une autre solution:

import ast
#necessary if string repr of lists
#df['yearly_cost'] = df['yearly_cost'].apply(ast.literal_eval)

from itertools import chain

df = pd.DataFrame({
    'yearly_cost' : list(chain.from_iterable(df['yearly_cost'].tolist())), 
    'date' : df['date'].values.repeat(df['yearly_cost'].str.len())
})

df = df.groupby('date', as_index=False)['yearly_cost'].mean()
print (df)
         date  yearly_cost
0  2009-01-01   435.046667
1  2009-01-02   366.113333
2  2009-01-03   327.408000


6 commentaires

Je reçois l'erreur suivante à la première étape TypeError: impossible de réduire avec le type flexible


Un autre problème est que la troisième date a la somme de deux moyennes plutôt que d'une seule moyenne de la journée entière.


@ geds133 - oui, la solution a donc changé


Je viens de recevoir MemoryError:


@ geds133 Quelle est la taille de vos données?


@piRSquared seulement 300 000 lignes



3
votes

IIUC

Supprimez la liste vide en convertissant le type en booléen.

df.groupby('date')['yearly_cost'].apply(lambda x : np.mean(x.sum()))

Après avoir supprimé la liste vide, vous pouvez faire groupby

df=df[df.yearly_cost.astype(bool)].copy()


3 commentaires

Recevez la même erreur que ci-dessus TypeError: impossible de réduire avec le type flexible


@ geds133 vous devez nous indiquer si la colonne 'annual_cost' est constituée de chaînes ou de listes.


@piRSquared Listes vides et listes avec des flottants



0
votes

groupby.sum et np.mean

La somme concaténera les listes.

i, u = df.date.factorize()
j = i.repeat([*map(len, df.yearly_cost)])
v = np.concatenate(df.yearly_cost)

c = np.bincount(j)
s = np.bincount(j, v)
pd.Series(s / c, u)

2009-01-01    435.046667
2009-01-02    366.113333
2009-01-03    327.408000
dtype: float64

Si ce sont des chaînes

df.groupby('date').yearly_cost.apply(lambda x: np.concatenate([*x]).mean())

ALT

from ast import literal_eval

df.yearly_cost.apply(literal_eval).groupby(df.date).sum().apply(np.mean)

Factoriser

df.groupby('date').yearly_cost.sum().apply(np.mean)

date
2009-01-01    435.046667
2009-01-02    366.113333
2009-01-03    327.408000
Name: yearly_cost, dtype: float64

3 commentaires

J'ai parlé trop tôt, il semble toujours y avoir des listes vides dans la série chronologique, car lorsque j'essaie de créer une moyenne mobile, j'obtiens cette erreur ValueError: impossible de convertir la chaîne en flottant: '[]'


@ geds133 J'obtiens ça quand je fais float ('[]') ce qui signifie que vous avez des chaînes dans vos données qui sont contraires à ce que vous avez affirmé. Cela signifie que vous avez de mauvaises données et que vous devez les nettoyer. Plusieurs utilisateurs ont suggéré literal_eval . Avant d'utiliser l'une des techniques, essayez de faire ceci df ['year_cost'] = df ['annual_cost']. Astype (str) .apply (literal_eval) . Assurez-vous de depuis ast import literal_eval


Est-il possible que les listes vides soient comptées comme des chaînes? Le df renvoyé est une série avec date comme index et pas de annual_cost .