Pandas update values in a multi-index dataframe - python

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

Related

Complete the index and columns in pandas(DataFrame)?

Here is a datafrmae.
a = pd.DataFrame({'a':np.arange(10)}, index=np.arange(0,20,2))
# then I can create new dataframe and complete the index.
b = pd.DataFrame(index=np.arange(20))
b['a'] = a
# Now convert the index np.arange(0,20,2) to np.arange(20). Fill noexists value by np.nan.
But how can i do the same way to column? Suppose the column's dtype is int32 and names is np.arange(0,20,2).
It seems you need reindex:
print (a.reindex(b.index))
a
0 0.0
1 NaN
2 1.0
3 NaN
4 2.0
5 NaN
6 3.0
7 NaN
8 4.0
9 NaN
10 5.0
11 NaN
12 6.0
13 NaN
14 7.0
15 NaN
16 8.0
17 NaN
18 9.0
19 NaN
Also can reindex columns:
a.columns = [0]
print (a.reindex(index=b.index, columns=np.arange(0,20,2)))
0 2 4 6 8 10 12 14 16 18
0 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 1.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 2.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6 3.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
7 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
8 4.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
9 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
10 5.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
11 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
12 6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
13 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
14 7.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
15 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
16 8.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
17 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
18 9.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
19 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

How can I rearrange the index level with Pandas?

The purpose of this post is to try to understand how best to manipulate dataframes with multilevels.
Create the dataframe
import numpy as np
dates = pd.date_range('20130101', periods=6)
df = pd.DataFrame(np.random.randn(6,4), index=dates, columns=list('WXYZ'))
df['Portfolio']= list('ABCDEF')
df
Dataframe
Y Z Portfolio
01/01/2013 1 2 A
02/01/2013 3 4 B
03/01/2013 5 6 C
04/01/2013 7 8 D
05/01/2013 9 10 E
06/01/2013 11 12 F
Pivot the dataframe
dfs_pivot = df.pivot(columns='Portfolio')
dfs_pivot
Pivoted Dateframe
Y Z
Portfolio A B C D E F A B C D E F
2013-01-01 1 NaN NaN NaN NaN NaN 2 NaN NaN NaN NaN NaN
2013-01-02 NaN 3 NaN NaN NaN NaN NaN 4 NaN NaN NaN NaN
2013-01-03 NaN NaN 5 NaN NaN NaN NaN NaN 6 NaN NaN NaN
2013-01-04 NaN NaN NaN 7 NaN NaN NaN NaN NaN 8 NaN NaN
2013-01-05 NaN NaN NaN NaN 9 NaN NaN NaN NaN NaN 10 NaN
2013-01-06 NaN NaN NaN NaN NaN 11 NaN NaN NaN NaN NaN 12
How can the levels be switched to give?
Portfolio A B C D E F
Y Z Y Z Y Z Y Z Y Z Y Z
2013-01-01 1 2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2013-01-02 NaN NaN 3 4 NaN NaN NaN NaN NaN NaN NaN NaN
2013-01-03 NaN NaN NaN NaN 5 6 NaN NaN NaN NaN NaN NaN
2013-01-04 NaN NaN NaN NaN NaN NaN 7 8 NaN NaN NaN NaN
2013-01-05 NaN NaN NaN NaN NaN NaN NaN NaN 9 10 NaN NaN
2013-01-06 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 11 12
To swap the order of the MultiIndex levels, use DataFrame.swaplevel:
import numpy as np
import pandas as pd
dates = pd.date_range('20130101', periods=6)
df = pd.DataFrame(np.random.randint(10, size=(6,2)), index=dates, columns=list('YZ'))
df['Portfolio']= list('ABCDEF')
dfs_pivot = df.pivot(columns='Portfolio').swaplevel(0, 1, axis=1)
yields
Portfolio A B C D E F A B C D E F
Y Y Y Y Y Y Z Z Z Z Z Z
2013-01-01 7.0 NaN NaN NaN NaN NaN 9.0 NaN NaN NaN NaN NaN
2013-01-02 NaN 4.0 NaN NaN NaN NaN NaN 3.0 NaN NaN NaN NaN
2013-01-03 NaN NaN 8.0 NaN NaN NaN NaN NaN 2.0 NaN NaN NaN
2013-01-04 NaN NaN NaN 5.0 NaN NaN NaN NaN NaN 7.0 NaN NaN
2013-01-05 NaN NaN NaN NaN 4.0 NaN NaN NaN NaN NaN 7.0 NaN
2013-01-06 NaN NaN NaN NaN NaN 3.0 NaN NaN NaN NaN NaN 9.0
To sort the columns call DataFrame.sortlevel:
dfs_pivot = dfs_pivot.sortlevel(axis=1)
yields
Portfolio A B C D E F
Y Z Y Z Y Z Y Z Y Z Y Z
2013-01-01 7.0 9.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2013-01-02 NaN NaN 4.0 3.0 NaN NaN NaN NaN NaN NaN NaN NaN
2013-01-03 NaN NaN NaN NaN 8.0 2.0 NaN NaN NaN NaN NaN NaN
2013-01-04 NaN NaN NaN NaN NaN NaN 5.0 7.0 NaN NaN NaN NaN
2013-01-05 NaN NaN NaN NaN NaN NaN NaN NaN 4.0 7.0 NaN NaN
2013-01-06 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 3.0 9.0
To rearrange the columns in a custom order, you could call reindex:
custom_order = [('E', 'Z'), ('D', 'Z'), ('C', 'Z'), ('F', 'Z'), ('F', 'Y'), ('B', 'Z'),
('C', 'Y'), ('E', 'Y'), ('A', 'Z'), ('A', 'Y'), ('B', 'Y'), ('D', 'Y')]
dfs_pivot = dfs_pivot.reindex(columns=custom_order)
or, more simply, use column-indexing syntax:
dfs_pivot = dfs_pivot[custom_order]
which yields
Portfolio E D C F B C E A B D
Z Z Z Z Y Z Y Y Z Y Y Y
2013-01-01 NaN NaN NaN NaN NaN NaN NaN NaN 9.0 7.0 NaN NaN
2013-01-02 NaN NaN NaN NaN NaN 3.0 NaN NaN NaN NaN 4.0 NaN
2013-01-03 NaN NaN 2.0 NaN NaN NaN 8.0 NaN NaN NaN NaN NaN
2013-01-04 NaN 7.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN 5.0
2013-01-05 7.0 NaN NaN NaN NaN NaN NaN 4.0 NaN NaN NaN NaN
2013-01-06 NaN NaN NaN 9.0 3.0 NaN NaN NaN NaN NaN NaN NaN

Pandas: Create view on MultiColumn object

I'm trying to set a value on a multi columned table. However, I appear to be working on a copy, as the value does not persist:
In[4]: tIndex = np.array([32, 34, 134, 234, 334, 434])
topColumns = ['homogenous', 'heterogenous']
mus = ['mu_el', 'mu_eh', 'mu_ul', 'mu_uh']
bottomColumns = mus + ['Jl', 'Jh', 'v', 'u']
arrays = [topColumns, bottomColumns]
#tuples = list(zip(*arrays))
columns = pd.MultiIndex.from_product(arrays)
df = pd.DataFrame(columns=columns, index=tIndex)
In[6]: df.loc[32, 'homogenous']['v'] = 1
In[8]: df.loc[32, 'homogenous']['v']
Out[8]: nan
The case of a multi-index inside .loc[] is trivial and mentioned extensively in the documentation. However, how do I work with a view with a multi-columned data frame?
You need to pass tuple to represent the different levels:
In [125]:
df.loc[32, ('homogenous','v')] = 1
df
Out[125]:
homogenous heterogenous \
mu_el mu_eh mu_ul mu_uh Jl Jh v u mu_el mu_eh mu_ul
32 NaN NaN NaN NaN NaN NaN 1 NaN NaN NaN NaN
34 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
134 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
234 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
334 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
434 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
mu_uh Jl Jh v u
32 NaN NaN NaN NaN NaN
34 NaN NaN NaN NaN NaN
134 NaN NaN NaN NaN NaN
234 NaN NaN NaN NaN NaN
334 NaN NaN NaN NaN NaN
434 NaN NaN NaN NaN NaN
it looks you're doing chained indexing

How to set the values of a dataframe given a series of indices and corresponding column names?

Assume I have a dataframe df1:
A B C D E
Date
2009-01-30 NaN NaN NaN NaN NaN
2009-02-02 NaN NaN NaN NaN NaN
2009-02-03 NaN NaN NaN NaN NaN
2009-02-04 NaN NaN NaN NaN NaN
2009-02-05 NaN NaN NaN NaN NaN
2009-02-06 NaN NaN NaN NaN NaN
2009-02-09 NaN NaN NaN NaN NaN
2009-02-10 NaN NaN NaN NaN NaN
and a Series:
Date
2009-02-04 A
2009-02-06 E
is there a fast vectorized view to set the index/columns values in df1 so as to obtain df2:
A B C D E
Date
2009-01-30 NaN NaN NaN NaN NaN
2009-02-02 NaN NaN NaN NaN NaN
2009-02-03 NaN NaN NaN NaN NaN
2009-02-04 1 NaN NaN NaN NaN
2009-02-05 NaN NaN NaN NaN NaN
2009-02-06 NaN NaN NaN NaN 1
2009-02-09 NaN NaN NaN NaN NaN
2009-02-10 NaN NaN NaN NaN NaN
import numpy as np
import pandas as pd
df1 = pd.DataFrame(np.nan, columns=list('ABCDE'), index=pd.to_datetime(
['2009-01-30', '2009-02-02', '2009-02-03', '2009-02-04', '2009-02-05',
'2009-02-06', '2009-02-09', '2009-02-10']))
ser = pd.Series(list('AE'), index=pd.to_datetime(['2009-02-04', '2009-02-06']))
freqs = pd.get_dummies(ser)
freqs = freqs.where(freqs != 0, np.nan)
result = df1.add(freqs, fill_value=0)
print(result)
pd.get_dummies can be used to convert your Series into a frequency table:
In [117]: freqs = pd.get_dummies(ser)
In [118]: freqs = freqs.where(freqs != 0, np.nan)
In [119]: freqs
Out[119]:
col_0 A E
row_0
2009-02-04 1 NaN
2009-02-06 NaN 1
and the DataFrame.add method can be used to add these values to df1:
In [124]: df1.add(freqs, fill_value=0)
Out[124]:
A B C D E
2009-01-30 NaN NaN NaN NaN NaN
2009-02-02 NaN NaN NaN NaN NaN
2009-02-03 NaN NaN NaN NaN NaN
2009-02-04 1 NaN NaN NaN NaN
2009-02-05 NaN NaN NaN NaN NaN
2009-02-06 NaN NaN NaN NaN 1
2009-02-09 NaN NaN NaN NaN NaN
2009-02-10 NaN NaN NaN NaN NaN

how to multiply multiple columns by a column in Pandas

I would like to have:
df[['income_1', 'income_2']] * df['mtaz_proportion']
return those columns multiplied by df['mtaz_proportion']
so that I can set
df[['mtaz_income_1', 'mtaz_income_2']] =
df[['income_1', 'income_2']] * df['mtaz_proportion']
but instead I get:
income_1 income_2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
ect...
what simple thing am I missing?
Thank you!
use multiply method and set axis="index":
df[["A", "B"]].multiply(df["C"], axis="index")
Another way of writing the answer of HYRY:
df.loc[:,['A', 'B']] = df.loc[:,['A', 'B']].multiply(df.loc[:, 'C'], axis="index")
Convert both factors to numpy arrays using to_numpy:
df.loc[:, ['D', 'E']] = df[['A', 'B']].to_numpy() * df[['C']].to_numpy()

Categories