Reputation: 784
I want to split the dataframe by specific dates and the cut-off level to be 31st of March. Meaning that everything that came before 31st of march should belong to a dataframe and everything after should belong to the next data frame and so on. The data looks like this:
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
Expected output:
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
My code so far is the following:
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
@Josh Friedlander, @Jeril and @KeepAlive solutions work as expected. Thank you all!
Upvotes: 1
Views: 518
Reputation: 6655
What about doing
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()
which has injected df1
, df2
, df3
and df4
in the global environment. Putting aside the discussion regarding if this is a good practice or not.
It is better to avoid playing directly inside the global environment like this: saving the truncated versions of df
inside, say, a dictionnary called dfs
, is advocated:
dfs = {}
#...
#...
dfs[y+1] = df.loc[
(min_date < df.date64) & (df.date64 <= max_date)
].copy()
or doing the same thing with a list
dfs = []
#...
#...
dfs.append(
df.loc[(min_date < df.date64) & (df.date64 <= max_date)].copy()
)
Upvotes: 1
Reputation: 11657
A better way is with Pandas built-in Period
:
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
Upvotes: 2
Reputation: 8521
I dint try running this code, but I guess it should work.
def getFiscalYear(dt):
year = dt.year
if dt.month<4: year -= 1
return year
df['year'] = df['date'].apply(getFiscalYear)
df.groupby('year')
Make sure the 'date' column is of type pd.datetime
. What we are doing here is, we are trying to create a column based on financial year, and grouping by based on that.
If you want to create a dataframe for each year, then you can iterate over the 'year' column and create new dataframe as you go.
df_dict = {}
for year in df['year'].unique():
df_dict[year] = df[df['year' == year]]
Upvotes: 2