how to convert dataframe to multi level dataframe in pandas - python

I have list and dataframe
list1 = ['one', 'two', 'three']
list2 = ['a', 'b']
df is
A B C D
0 NaN NaN NaN NaN
1 NaN NaN NaN NaN
then how to convert into multilevel indexing dataframe which as follows
A B C D
one two three a b
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN
or
A B
one two three a b C D
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN

Related

Pandas update values in a multi-index dataframe

How can I edit a values of a multi-index dataframe? If it was a non-multi-index dataframe, I know I could do this: df.at[0,'foo'] = 12.3.
Also, this does not work: df.loc[0]['foo']['a'] = 12.3.
Consider a multi-index column dataframe.
colnames = [
['foo', 'foo', 'foo', 'po', 'po', 'po', 'di', 'di', 'di'],
['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']
]
df = pd.DataFrame(columns=colnames, index=arange(5))
display(df)
foo po di
a b c a b c a b c
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN
Use tuples for select MultiIndex in columns:
df.loc[0, ('foo','a')] = 12.3
print (df)
foo po di
a b c a b c a b c
0 12.3 NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN
If need more complicated updating use slicers:
idx = pd.IndexSlice
df.loc[0, idx['foo', ['b','c']]] = 12.3
print (df)
foo po di
a b c a b c a b c
0 NaN 12.3 12.3 NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN
df.loc[0, idx[:, ['b','c']]] = 12.3
print (df)
foo po di
a b c a b c a b c
0 NaN 12.3 12.3 NaN 12.3 12.3 NaN 12.3 12.3
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN
df.loc[:, idx[['po','di'], 'a']] = 12.3
print (df)
foo po di
a b c a b c a b c
0 NaN NaN NaN 12.3 NaN NaN 12.3 NaN NaN
1 NaN NaN NaN 12.3 NaN NaN 12.3 NaN NaN
2 NaN NaN NaN 12.3 NaN NaN 12.3 NaN NaN
3 NaN NaN NaN 12.3 NaN NaN 12.3 NaN NaN
4 NaN NaN NaN 12.3 NaN NaN 12.3 NaN NaN

Pandas dataframe of dataframes with hierarchical columns

I have a hierarchical dataframe I created in pandas:
import pandas as pd
import numpy as np
col_index = pd.MultiIndex.from_product([[0,1], ['a', 'b', 'c']])
df_outer = pd.DataFrame(index=range(4), columns=col_index)
print(df_outer)
0 1
a b c a b c
0 NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN
I'm wondering if it's possible to populate each entry in this data frame with another data frame, for example:
inner_names = ['w', 'x', 'y', 'z']
df_inner = pd.DataFrame(np.random.randn(4,4), index=inner_names, columns=inner_names)
If this is a bad idea, what would be a better way to create some othe easily indexed data structure containing data frames I want to put in the lements of df_outer?
It is a bit crazy, because need 3 levels in columns and 2 levels in indices and then assign by selecting with slicers:
np.random.seed(452)
col_index = pd.MultiIndex.from_product([[0,1], ['a', 'b', 'c'], ['w', 'x']])
idx = pd.MultiIndex.from_product([range(2), ['w', 'x']])
df_outer = pd.DataFrame(columns=col_index, index=idx)
print(df_outer)
0 1
a b c a b c
w x w x w x w x w x w x
0 w NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
x NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 w NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
x NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
inner_names = ['w', 'x']
df_inner = pd.DataFrame(np.random.randn(2,2), index=inner_names, columns=inner_names)
print(df_inner)
w x
w -0.182421 0.962712
x -0.118524 -0.784380
idx = pd.IndexSlice
df_outer.loc[idx[0,:], idx[0, 'a', :]]= df_inner.values
print(df_outer)
0 1
a b c a b c
w x w x w x w x w x w x
0 w -0.182421 0.962712 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
x -0.118524 -0.78438 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 w NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
x NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

Pandas- How to append a transpose of dataframe to another dataframe as column headers?

I need to add DF1 values as column in DF2
DataFrame1
DataFrame2 (in which append operation is required)
Required DataFrame - DF3
Try pd.concat with an empty dataframe consisting only of headers. Here's a demo -
df1
A B
0 -0.820067 -0.078793
1 -0.341793 -0.301040
2 -0.122264 1.163896
3 -1.693027 0.147647
4 -1.322206 1.839631
5 0.902077 0.334976
6 0.628941 -1.252080
7 0.607116 -0.588056
8 0.564448 0.096036
9 -0.863496 0.345668
df2
HeaderName
0 XYZ
1 ABC
2 SRT
3 FFF
pd.concat([df1, pd.DataFrame(columns=df2.HeaderName)], 1)
A B XYZ ABC SRT FFF
0 -0.820067 -0.078793 NaN NaN NaN NaN
1 -0.341793 -0.301040 NaN NaN NaN NaN
2 -0.122264 1.163896 NaN NaN NaN NaN
3 -1.693027 0.147647 NaN NaN NaN NaN
4 -1.322206 1.839631 NaN NaN NaN NaN
5 0.902077 0.334976 NaN NaN NaN NaN
6 0.628941 -1.252080 NaN NaN NaN NaN
7 0.607116 -0.588056 NaN NaN NaN NaN
8 0.564448 0.096036 NaN NaN NaN NaN
9 -0.863496 0.345668 NaN NaN NaN NaN
Use DataFrame.join:
df2 = df1.join(pd.DataFrame(columns=df2['HeaderName']))
Or assign:
df2 = df1.assign(**pd.Series(index=df2['HeaderName']))
We can using reindex
df1.reindex(columns=list(df1)+df2.HeaderName.tolist())
Out[754]:
A B XYZ ABC SRT FFF
0 -0.820067 -0.078793 NaN NaN NaN NaN
1 -0.341793 -0.301040 NaN NaN NaN NaN
2 -0.122264 1.163896 NaN NaN NaN NaN
3 -1.693027 0.147647 NaN NaN NaN NaN
4 -1.322206 1.839631 NaN NaN NaN NaN
5 0.902077 0.334976 NaN NaN NaN NaN
6 0.628941 -1.252080 NaN NaN NaN NaN
7 0.607116 -0.588056 NaN NaN NaN NaN
8 0.564448 0.096036 NaN NaN NaN NaN
9 -0.863496 0.345668 NaN NaN NaN NaN

Pandas Loc select by index as well as boolean condition in single expression

I have a simplified Dataframe which can be set up as follows:
indexes =['01/10/2017', '28/10/2018', '27/10/2019', '30/10/2019']
cols = ['Period', 'A', 'B', 'C']
df= pd.DataFrame(index = indexes, columns= cols)
df.Period = 1
df = pd.concat([df, 2*df.copy(), 3*df.copy()])
df.sort_index()
The Dataframe looks like:
Period A B C
01/10/2017 1 NaN NaN NaN
01/10/2017 2 NaN NaN NaN
01/10/2017 3 NaN NaN NaN
27/10/2019 1 NaN NaN NaN
27/10/2019 2 NaN NaN NaN
27/10/2019 3 NaN NaN NaN
28/10/2018 1 NaN NaN NaN
28/10/2018 2 NaN NaN NaN
28/10/2018 3 NaN NaN NaN
30/10/2019 1 NaN NaN NaN
30/10/2019 2 NaN NaN NaN
30/10/2019 3 NaN NaN NaN
I want to find the rows that are in this list:
FwdTimeChangeDates = ['28/10/2018', '27/10/2019']
with Period that is > 2.
I want to +=2 to the Period with those conditions (So Period 3-->5, and 4-->6, etc.).
How do I filter based on the two conditions?
df.loc[FwdTimeChangeDates] Gives:
Period A B C
28/10/2018 1 NaN NaN NaN
28/10/2018 2 NaN NaN NaN
28/10/2018 3 NaN NaN NaN
27/10/2019 1 NaN NaN NaN
27/10/2019 2 NaN NaN NaN
27/10/2019 3 NaN NaN NaN
and
df.loc[df.Period>2]
Gives
Period A B C
01/10/2017 3 NaN NaN NaN
28/10/2018 3 NaN NaN NaN
27/10/2019 3 NaN NaN NaN
30/10/2019 3 NaN NaN NaN
and I want:
Period A B C
28/10/2018 3 NaN NaN NaN
27/10/2019 3 NaN NaN NaN
But I can't join the two conditions with:
df.loc[FwdTimeChangeDates & df.Period>1] or
df.loc[(FwdTimeChangeDates) & (df.Period>1)]
Combine the two conditions, use isin for the first.
df[df.index.isin(['28/10/2018', '27/10/2019']) & (df.Period > 2)]
Period A B C
28/10/2018 3 NaN NaN NaN
27/10/2019 3 NaN NaN NaN
If the dataframe has a multiindex:
df.loc[(df.index.isin(FwdTimeChangeDates, level=0)) & (df.Period > 2), 'Period']
You can split two conditions
df.loc[FwdTimeChangeDates].query('Period>2')
Out[1366]:
Period A B C
28/10/2018 3 NaN NaN NaN
27/10/2019 3 NaN NaN NaN

How to do join of multiindex dataframe with another multiindex dataframe?

This is to go further from the following thread:
How to do join of multiindex dataframe with a single index dataframe?
The multi-indices of df1 are sublevel indices of df2.
In [1]: import pandas as pd
In [2]: import numpy as np
In [3]: import itertools
In [4]: inner = ('a','b')
In [5]: outer = ((10,20), (1,2))
In [6]: cols = ('one','two','three','four')
In [7]: sngl = pd.DataFrame(np.random.randn(2,4), index=inner, columns=cols)
In [8]: index_tups = list(itertools.product(*(outer + (inner,))))
In [9]: index_mult = pd.MultiIndex.from_tuples(index_tups)
In [10]: mult = pd.DataFrame(index=index_mult, columns=cols)
In [11]: sngl
Out[11]:
one two three four
a 2.946876 -0.751171 2.306766 0.323146
b 0.192558 0.928031 1.230475 -0.256739
In [12]: mult
Out[12]:
one two three four
10 1 a NaN NaN NaN NaN
b NaN NaN NaN NaN
2 a NaN NaN NaN NaN
b NaN NaN NaN NaN
20 1 a NaN NaN NaN NaN
b NaN NaN NaN NaN
2 a NaN NaN NaN NaN
b NaN NaN NaN NaN
In [13]: mult.ix[(10,1)] = sngl
In [14]: mult
Out[14]:
one two three four
10 1 a NaN NaN NaN NaN
b NaN NaN NaN NaN
2 a NaN NaN NaN NaN
b NaN NaN NaN NaN
20 1 a NaN NaN NaN NaN
b NaN NaN NaN NaN
2 a NaN NaN NaN NaN
b NaN NaN NaN NaN
# the new dataframes
sng2=pd.concat([sng1,sng1],keys=['X','Y'])
mult2=pd.concat([mult,mult],keys=['X','Y'])
In [110]:
sng2
Out[110]:
one two three four
X a 0.206810 -1.056264 -0.572809 -0.314475
b 0.514873 -0.941380 0.132694 -0.682903
Y a 0.206810 -1.056264 -0.572809 -0.314475
b 0.514873 -0.941380 0.132694 -0.682903
In [121]: mult2
Out[121]:
one two three four
X 10 1 a NaN NaN NaN NaN
b NaN NaN NaN NaN
2 a NaN NaN NaN NaN
b NaN NaN NaN NaN
20 1 a NaN NaN NaN NaN
b NaN NaN NaN NaN
2 a NaN NaN NaN NaN
b NaN NaN NaN NaN
Y 10 1 a NaN NaN NaN NaN
b NaN NaN NaN NaN
2 a NaN NaN NaN NaN
b NaN NaN NaN NaN
20 1 a NaN NaN NaN NaN
b NaN NaN NaN NaN
2 a NaN NaN NaN NaN
b NaN NaN NaN NaN
the code above is long, please scroll
The two multilevel indices of sng2 share the 1st and 4th indices of mul2. ('X','a') for example.
#DSM proposed a solution to work with a multiindex df2 and single index df1
mult[:] = sngl.loc[mult.index.get_level_values(2)].values
BUt DataFrame.index.get_level_values(2) can only work for one level of index.
It's not clear from the question which index levels the data frames share. I think you need to revise the set-up code as it gives an error at the definition of sngl. Anyway, suppose mult shares the first and second level with sngl you can just drop the second level from the index of mult and index in:
mult[:] = sngl.loc[mult.index.droplevel(2)].values
On a side note, you can construct a multi index from a product directly using pd.MultiIndex.from_product rather than using itertools

Categories