Je souhaite diviser le dataframe par des dates spécifiques et le niveau limite au 31 mars. Cela signifie que tout ce qui est arrivé avant le 31 mars devrait appartenir à une trame de données et tout ce qui suit devrait appartenir à la trame de données suivante et ainsi de suite. Les données ressemblent à ceci:
import pandas as pd
path = 'C:/Users/Adrian/Desktop/'
df = pd.read_csv(path + "trailing.csv", low_memory=False, usecols=[0, 3, 6])
df.rename(columns={'report_dte': 'date'}, inplace=True)
df['date'] = pd.to_datetime(df['date'], format="%d/%m/%Y")
df = df.sort_values(["date"], ascending=True)
df['t_rev'] = 0
df2 = df.groupby("c_name")
counter = 0
for c_name, df_name in df2:
counter += 1
print(df_name.sort_values(['date'], ascending=True))
print(len(df_name.index))
if counter == 1:
break
Résultat attendu:
df1:
c_name date revenue t_rev
310260 1-800 CONTACTS INC 1997-01-31 3.628 0
df2:
c_name date revenue t_rev
296014 1-800 CONTACTS INC 1998-01-31 6.970 0
df3:
c_name date revenue t_rev
291248 1-800 CONTACTS INC 1998-05-06 10.429 0
287356 1-800 CONTACTS INC 1998-08-11 12.801 0
283720 1-800 CONTACTS INC 1998-11-10 18.419 0
279837 1-800 CONTACTS INC 1999-02-24 18.227 0
df4:
c_name date revenue t_rev
277333 1-800 CONTACTS INC 1999-04-27 22.304 0
274650 1-800 CONTACTS INC 1999-07-20 23.960 0
269885 1-800 CONTACTS INC 1999-10-26 26.890 0
265851 1-800 CONTACTS INC 2000-02-07 25.371 0
Mon code pour l'instant est le suivant:
c_name date revenue t_rev 310260 1-800 CONTACTS INC 1997-01-31 3.628 0 296014 1-800 CONTACTS INC 1998-01-31 6.970 0 291248 1-800 CONTACTS INC 1998-05-06 10.429 0 287356 1-800 CONTACTS INC 1998-08-11 12.801 0 283720 1-800 CONTACTS INC 1998-11-10 18.419 0 279837 1-800 CONTACTS INC 1999-02-24 18.227 0 277333 1-800 CONTACTS INC 1999-04-27 22.304 0 274650 1-800 CONTACTS INC 1999-07-20 23.960 0 269885 1-800 CONTACTS INC 1999-10-26 26.890 0 265851 1-800 CONTACTS INC 2000-02-07 25.371 0
Les solutions @Josh Friedlander, @Jeril et @KeepAlive fonctionnent comme prévu. Merci à tous!
3 Réponses :
Je n'ai pas essayé d'exécuter ce code, mais je suppose que cela devrait fonctionner.
df_dict = {}
for year in df['year'].unique():
df_dict[year] = df[df['year' == year]]
Assurez-vous que la colonne 'date' est de type pd.datetime . Ce que nous faisons ici, c'est que nous essayons de créer une colonne basée sur l'exercice, et de regrouper en fonction de cela.
Si vous souhaitez créer une base de données pour chaque année, vous pouvez parcourir le colonne "année" et créez une nouvelle trame de données au fur et à mesure.
def getFiscalYear(dt):
year = dt.year
if dt.month<4: year -= 1
return year
df['year'] = df['date'].apply(getFiscalYear)
df.groupby('year')
Au lieu de df [df ['year' == year]] utilisez df.loc [df ['year'] == year]
Que diriez-vous de faire
dfs = []
#...
#...
dfs.append(
df.loc[(min_date < df.date64) & (df.date64 <= max_date)].copy()
)
qui a injecté df1 , df2 , df3 et df4 dans l'environnement global. Mettre de côté la discussion pour savoir si c'est une bonne pratique ou non.
Il vaut mieux éviter de jouer directement à l'intérieur de l'environnement global comme ceci: enregistrer les versions tronquées de df code > à l'intérieur, par exemple, d'un dictionnaire appelé dfs , est recommandé:
dfs = {}
#...
#...
dfs[y+1] = df.loc[
(min_date < df.date64) & (df.date64 <= max_date)
].copy()
ou faire la même chose avec un liste
import datetime as dt
years = range(1997, 2000 + 1)
df['date64'] = df.date.astype("datetime64")
for y,year in enumerate(years):
min_date = dt.datetime(year , 3, 31)
max_date = dt.datetime(year + 1, 3, 31)
globals()[f'df{y+1}'] = df.loc[
(min_date < df.date64) & (df.date64 <= max_date)
].copy()
Mettre de côté la discussion pour savoir si c'est une bonne pratique ou non. - Je pense que c'est vraiment une mauvaise pratique, beaucoup mieux est dict
@Adrian ça marche? Je ne peux pas tester mon code maintenant.
@keepAlive jusqu'à présent, le code de votre solution ne fonctionne pas comme prévu, mais c'est peut-être à cause de moi .. J'ai inclus dans la question initiale comment j'ai essayé de mettre en œuvre votre solution.
@Adrian. C'est parce que lorsque vous faites pour élément dans dfs: print ("chaque élément", élément) , vous n'imprimez pas les éléments en tant que tels, mais leur clé associée dans le dictionnaire. Faites pour clé, élément dans dfs.items (): print ("chaque élément", clé, élément)
@keepAlive Oui, j'ai totalement oublié que vous devez itérer différemment sur les dictionnaires par rapport aux listes. Merci et désolé de vous avoir autant dérangé
Si ce que je propose fonctionne comme prévu, peut-être simplement modifier votre question pour refléter cela? :) ... Merci :)
@keepAlive Oui, je viens de faire ça: D
Un meilleur moyen est d'utiliser les Period intégrés de Pandas :
df['year'] = df.date.dt.to_period('A-MAR') # assigns years ending in March
dfs = [df.loc[df.year == year] for year in df.year.unique()]
# gives list of dfs divided by year
Votre code fonctionne comme prévu, mais il y a une petite erreur qui apparaît en haut: A: / python project / trailing_accounts / read_excel.py: 32: SettingWithCopyWarning: Une valeur essaie d'être définie sur une copie d'une tranche à partir d'un DataFrame. Essayez d'utiliser .loc [row_indexer, col_indexer] = value à la place Savez-vous ce qui pourrait en être la cause?
read_excel est le nom du fichier .py. Au départ, je travaillais avec Excel et non avec des CSV. Changé maintenant en read_csv pour correspondre au problème en cours. La ligne 32 est celle-ci: df_name ['year'] = df_name.date.dt.to_period ('A-MAR') J'ai changé le df en df_name car j'ai d'abord besoin de regrouper les données par nom puis faites le regroupement par année
est-ce réglé?
oui, le problème est réglé. Merci beaucoup pour votre temps.
Vous êtes le bienvenu :) Je pense que ma réponse serait plus rapide / plus idiomatique que d'utiliser apply comme l'a suggéré Jeril mais si les performances ne sont pas une préoccupation majeure, peu importe ce qui fonctionne ...
Mieux vaut utiliser
locet attribuer de nouveaux dfs que d'utilisergroupby@JoshFriedlander Désolé de vous déranger, pouvez-vous expliquer un peu plus, s'il vous plaît? Dois-je utiliser loc pour diviser le dataframe en dataframes pour chaque entreprise? Ou que voulez-vous dire exactement?
Voir la réponse de Jeril, mais la deuxième partie - c'est ce que je suggère