ReArrange Pandas DataFrame date columns in date order - python

I have a pandas dataframe that summarises sales by calendar month & outputs something like:
Month level_0 UNIQUE_ID 102018 112018 12018 122017 122018 22018 32018 42018 52018 62018 72018 82018 92018
0 SOLD_QUANTITY 01 3692.0 5182.0 3223.0 1292.0 2466.0 2396.0 2242.0 2217.0 3590.0 2593.0 1665.0 3371.0 3069.0
1 SOLD_QUANTITY 011 3.0 6.0 NaN NaN 7.0 5.0 2.0 1.0 5.0 NaN 1.0 1.0 3.0
2 SOLD_QUANTITY 02 370.0 130.0 NaN NaN 200.0 NaN NaN 269.0 202.0 NaN 201.0 125.0 360.0
3 SOLD_QUANTITY 03 2.0 6.0 NaN NaN 2.0 1.0 NaN 6.0 11.0 9.0 2.0 3.0 5.0
4 SOLD_QUANTITY 08 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 175.0 NaN NaN
I want to be able to programmatically re-arrange the column headers in ascending date order (eg starting 122017, 12018, 22018...). I need to do it in a way that is programmatic as every way the report runs, it will be a different list of months as it runs every month for last 365 days.
The index data type:
Index(['level_0', 'UNIQUE_ID', '102018', '112018', '12018', '122017', '122018',
'22018', '32018', '42018', '52018', '62018', '72018', '82018', '92018'],
dtype='object', name='Month')

Use set_index for only dates columns, convert them to datetimes and get order positions by argsort, then change ordering with iloc:
df = df.set_index(['level_0','UNIQUE_ID'])
df = df.iloc[:, pd.to_datetime(df.columns, format='%m%Y').argsort()].reset_index()
print (df)
level_0 UNIQUE_ID 122017 12018 22018 32018 42018 52018 \
0 SOLD_QUANTITY 1 1292.0 3223.0 2396.0 2242.0 2217.0 3590.0
1 SOLD_QUANTITY 11 NaN NaN 5.0 2.0 1.0 5.0
2 SOLD_QUANTITY 2 NaN NaN NaN NaN 269.0 202.0
3 SOLD_QUANTITY 3 NaN NaN 1.0 NaN 6.0 11.0
4 SOLD_QUANTITY 8 NaN NaN NaN NaN NaN NaN
62018 72018 82018 92018 102018 112018 122018
0 2593.0 1665.0 3371.0 3069.0 3692.0 5182.0 2466.0
1 NaN 1.0 1.0 3.0 3.0 6.0 7.0
2 NaN 201.0 125.0 360.0 370.0 130.0 200.0
3 9.0 2.0 3.0 5.0 2.0 6.0 2.0
4 NaN 175.0 NaN NaN NaN NaN NaN
Another idea is create month period index by DatetimeIndex.to_period, so is possible use sort_index:
df = df.set_index(['level_0','UNIQUE_ID'])
df.columns = pd.to_datetime(df.columns, format='%m%Y').to_period('m')
#alternative for convert to datetimes
#df.columns = pd.to_datetime(df.columns, format='%m%Y')
df = df.sort_index(axis=1).reset_index()
print (df)
level_0 UNIQUE_ID 2017-12 2018-01 2018-02 2018-03 2018-04 \
0 SOLD_QUANTITY 1 1292.0 3223.0 2396.0 2242.0 2217.0
1 SOLD_QUANTITY 11 NaN NaN 5.0 2.0 1.0
2 SOLD_QUANTITY 2 NaN NaN NaN NaN 269.0
3 SOLD_QUANTITY 3 NaN NaN 1.0 NaN 6.0
4 SOLD_QUANTITY 8 NaN NaN NaN NaN NaN
2018-05 2018-06 2018-07 2018-08 2018-09 2018-10 2018-11 2018-12
0 3590.0 2593.0 1665.0 3371.0 3069.0 3692.0 5182.0 2466.0
1 5.0 NaN 1.0 1.0 3.0 3.0 6.0 7.0
2 202.0 NaN 201.0 125.0 360.0 370.0 130.0 200.0
3 11.0 9.0 2.0 3.0 5.0 2.0 6.0 2.0
4 NaN NaN 175.0 NaN NaN NaN NaN NaN

Related

How to find the cumprod for dataframe by reserving the row values?

I have dataframe df:
0 1 2 3 4 5 6
Row Labels
2017 A1 2.0 2.0 NaN 2.0 NaN 2.0 NaN
2017 A2 2.0 2.0 2.0 NaN 2.0 2.0 NaN
2017 A3 2.0 2.0 2.0 2.0 2.0 2.0 NaN
2017 A4 2.0 2.0 2.0 2.0 2.0 2.0 NaN
2018 A1 2.0 2.0 2.0 2.0 NaN NaN NaN
2019 A2 2.0 2.0 2.0 NaN NaN NaN NaN
2020 A3 2.0 2.0 NaN NaN NaN NaN NaN
2021 A4 2.0 NaN NaN NaN NaN NaN NaN
I have to find the cumprod of the dataframe by reversing row values:
I tried this code ;
df1 = df[::-1].cumprod(axis=1)[::-1]
i got output like this ,
0 1 2 3 4 5 6
Row Labels
2017 A1 2.0 4.0 NaN 8.0 NaN 16.0 NaN
2017 A2 2.0 4.0 8.0 NaN 16.0 32.0 NaN
2017 A3 2.0 4.0 8.0 16.0 32.0 64.0 NaN
2017 A4 2.0 4.0 8.0 16.0 32.0 64.0 NaN
2018 A1 2.0 4.0 8.0 16.0 NaN NaN NaN
2019 A2 2.0 4.0 8.0 NaN NaN NaN NaN
2020 A3 2.0 4.0 NaN NaN NaN NaN NaN
2021 A4 2.0 NaN NaN NaN NaN NaN NaN
But expected output is ;
0 1 2 3 4 5 6
Row Labels
2017 A1 16.0 8.0 NaN 4.0 NaN 2.0 NaN
2017 A2 32.0 16.0 8.0 NaN 4.0 2.0 NaN
2017 A3 64.0 32.0 16.0 8.0 4.0 2.0 NaN
2017 A4 64.0 32.0 16.0 8.0 4.0 2.0 NaN
2018 A1 16.0 8.0 4.0 2.0 NaN NaN NaN
2019 A2 8.0 4.0 2.0 NaN NaN NaN NaN
2020 A3 4.0 2.0 NaN NaN NaN NaN NaN
2021 A4 2.0 NaN NaN NaN NaN NaN NaN
Thank You For Your Time :)
Use DataFrame.iloc with first : for select all rows and ::-1 for swapping by columns:
df1 = df.iloc[:, ::-1].cumprod(axis=1).iloc[:, ::-1]
print (df1)
0 1 2 3 4 5 6
Row Labels
2017 A1 16.0 8.0 NaN 4.0 NaN 2.0 NaN
2017 A2 32.0 16.0 8.0 NaN 4.0 2.0 NaN
2017 A3 64.0 32.0 16.0 8.0 4.0 2.0 NaN
2017 A4 64.0 32.0 16.0 8.0 4.0 2.0 NaN
2018 A1 16.0 8.0 4.0 2.0 NaN NaN NaN
2019 A2 8.0 4.0 2.0 NaN NaN NaN NaN
2020 A3 4.0 2.0 NaN NaN NaN NaN NaN
2021 A4 2.0 NaN NaN NaN NaN NaN NaN

Convert two pandas rows into one

I want to convert below dataframe,
ID TYPE A B
0 1 MISSING 0.0 0.0
1 2 1T 1.0 2.0
2 2 2T 3.0 4.0
3 3 MISSING 0.0 0.0
4 4 2T 10.0 4.0
5 5 CBN 15.0 20.0
6 5 DSV 25.0 35.0
to:
ID MISSING_A MISSING_B 1T_A 1T_B 2T_A 2T_B CBN_A CBN_B DSV_A DSV_B
0 1 0.0 0.0 NaN NaN NaN NaN NaN NaN NaN NaN
1 2 NaN NaN 1.0 2.0 3.0 4.0 NaN NaN NaN NaN
3 3 0.0 0.0 NaN NaN NaN NaN NaN NaN NaN NaN
4 4 10.0 4.0 NaN NaN 10.0 4.0 NaN NaN NaN NaN
5 5 NaN NaN NaN NaN NaN NaN 15.0 20.0 25.0 35.0
For IDs with multiple types, multiple rows for A and B to merge into one row as shown above.
You are looking for a pivot, which will end up giving you a multi-index. You'll need to join those columns to get the suffix you are looking for.
df = df.pivot(index='ID',columns='TYPE', values=['A','B'])
df.columns = ['_'.join(reversed(col)).strip() for col in df.columns.values]
df.reset_index()

Take derivative of dataframe

I want to take the derivative of a dataframe row-wise. This is simply the difference: df_derived(i,j) = df(i,j)- df(i,j-1). Dataframe given below:
GRD1 GRD2 GRD3 GRD4 GRD5 GRD6 GRD7
0 1 6 5.0 9.0 1.0 7.0 9
1 5 8 NaN 8.0 NaN NaN 2
2 7 8 NaN NaN NaN 2.0 6
I am looking for:
GRD1 GRD2 GRD3 GRD4 GRD5 GRD6 GRD7
0 NaN 5.0 -1 4.0 -8.0 6.0 2.0
1 NaN 3.0 NaN NaN NaN NaN NaN
2 NaN 1.0 NaN NaN NaN NaN 4.0
But when I do: df.apply('diff',axis=1), result is different:
GRD1 GRD2 GRD3 GRD4 GRD5 GRD6 GRD7
0 NaN 5.0 NaN 4.0 -8.0 6.0 3.0
1 NaN 3.0 NaN NaN NaN NaN -6.0
2 NaN 1.0 NaN NaN NaN NaN -2.0
Notice column GR3 and GRD7 are different.
How to do this?
Let us try numpy diff
df[:]=np.hstack([np.ones((len(df),1))*np.nan,np.diff(df.values)])
df
GRD1 GRD2 GRD3 GRD4 GRD5 GRD6 GRD7
0 NaN 5.0 -1.0 4.0 -8.0 6.0 2.0
1 NaN 3.0 NaN NaN NaN NaN NaN
2 NaN 1.0 NaN NaN NaN NaN 4.0
Try cast all columns to float
df_final = df.astype(float).diff(axis=1)
Out[65]:
GRD1 GRD2 GRD3 GRD4 GRD5 GRD6 GRD7
0 NaN 5.0 -1.0 4.0 -8.0 6.0 2.0
1 NaN 3.0 NaN NaN NaN NaN NaN
2 NaN 1.0 NaN NaN NaN NaN 4.0

Pandas long to wide with values filled based on answer

I am trying to convert a dataframe from long to wide, but Im not sure how to convert it to the format below. What am I missing?
d = {'vote': [100, 50,1,23,55,67,89,44],
'vote2': [10, 2,18,26,77,99,9,40],
'ballot1': ['a','b','a','a','b','a','a','b'],
'voteId':[1,2,3,4,5,6,7,8]}
df1=pd.DataFrame(d)
#########################################################
dftemp=df1
#####FORMATTING DATA
dftemp=pd.DataFrame(dftemp.reset_index())
dflw= dftemp.set_index(['voteId','vote','ballot1'])
dflw=dflw.unstack()
dflw.columns = dflw.columns.droplevel(0).rename('')
dflw=pd.DataFrame(dflw)
print(dflw)
MY CURRENT OUTPUT:
a b a b
voteId vote
1 100 0.0 NaN 10.0 NaN
2 50 NaN 1.0 NaN 2.0
GOAL:
voteid (ballot1=a)vote (ballot1=b)vote (ballot1=a)vote2 (ballot1=b)vote2
1 100 NaN 10 NaN
2 NaN 50 NaN 2
I am starting from df1
s=df1.set_index(['voteId','ballot1']).unstack()
s.columns=s.columns.map('(ballot1={0[1]}){0[0]}'.format)
s
Out[1120]:
(ballot1=a)vote (ballot1=b)vote (ballot1=a)vote2 (ballot1=b)vote2
voteId
1 100.0 NaN 10.0 NaN
2 NaN 50.0 NaN 2.0
3 1.0 NaN 18.0 NaN
4 23.0 NaN 26.0 NaN
5 NaN 55.0 NaN 77.0
6 67.0 NaN 99.0 NaN
7 89.0 NaN 9.0 NaN
8 NaN 44.0 NaN 40.0

Converting row in timeseries data to column

Suppose that I have a timeseries like
In [41]: df = pd.DataFrame(dict(names=list('abcaabcabbcc'), vals=np.random.randint(0, 10, 12)), index
...: =pd.date_range('2017-03-01', periods=12))
In [42]: df
Out[42]:
names vals
2017-03-01 a 2
2017-03-02 b 9
2017-03-03 c 6
2017-03-04 a 6
2017-03-05 a 5
2017-03-06 b 2
2017-03-07 c 3
2017-03-08 a 1
2017-03-09 b 1
2017-03-10 b 1
2017-03-11 c 1
2017-03-12 c 0
How can I convert the names row into the column headers, under which the corresponding vals are? e.g.
a b c
2017-03-01 2 nan nan
2017-03-02 nan 9 nan
...
I have been playing around with pd.melt as well as trying to add the names to the index and then reset the index so that they become columns somehow, but I am very stuck.
You can use:
print (pd.pivot(index=df.index, columns=df['names'], values=df['vals']))
Or:
print (df.set_index('names', append=True)['vals'].unstack())
names a b c
2017-03-01 4.0 NaN NaN
2017-03-02 NaN 0.0 NaN
2017-03-03 NaN NaN 3.0
2017-03-04 8.0 NaN NaN
2017-03-05 0.0 NaN NaN
2017-03-06 NaN 0.0 NaN
2017-03-07 NaN NaN 9.0
2017-03-08 6.0 NaN NaN
2017-03-09 NaN 6.0 NaN
2017-03-10 NaN 0.0 NaN
2017-03-11 NaN NaN 3.0
2017-03-12 NaN NaN 9.0
print (df.reset_index().pivot_table(index='index', columns='names', values='vals'))
you can also use unstack():
In [12]: df.set_index('names', append=True).unstack('names')
Out[12]:
vals
names a b c
2017-03-01 1.0 NaN NaN
2017-03-02 NaN 4.0 NaN
2017-03-03 NaN NaN 5.0
2017-03-04 8.0 NaN NaN
2017-03-05 8.0 NaN NaN
2017-03-06 NaN 5.0 NaN
2017-03-07 NaN NaN 7.0
2017-03-08 5.0 NaN NaN
2017-03-09 NaN 7.0 NaN
2017-03-10 NaN 4.0 NaN
2017-03-11 NaN NaN 3.0
2017-03-12 NaN NaN 4.0

Categories

Resources