I have a simple df like below:
ID Provider Single_Cost Bundle_ID Bundle_Cost
0 L_0001 P_01 1075.0 NaN NaN
1 L_0002 P_02 590.0 NaN NaN
2 L_0003 P_02 6900.0 NaN NaN
3 L_0004 P_02 625.0 NaN NaN
4 L_0005 P_02 5775.0 NaN NaN
5 L_0006 P_02 495.0 NaN NaN
6 L_0007 P_02 570.0 NaN NaN
7 L_0008 P_02 1250.0 NaN NaN
8 L_0009 P_03 2940.0 P_03_1 1470.0
9 L_0010 P_03 7608.0 P_03_1 7308.0
And I need to transform it to get 2 levels of columns:
Level 1: Provider (the number of providers varies)
Level 2: Single_Cost, Bundle_ID and Bundle_Cost (constant 3 columns for all providers)
Provider P_01 P_02 P_03
ID Single_Cost Bundle_ID Bundle_Cost Single_Cost Bundle_ID Bundle_Cost Single_Cost Bundle_ID Bundle_Cost
0 L_0001 1075.0 NaN NaN NaN NaN NaN NaN NaN NaN
1 L_0002 NaN NaN NaN 590.0 NaN NaN NaN NaN NaN
2 L_0003 NaN NaN NaN 6900.0 NaN NaN NaN NaN NaN
3 L_0004 NaN NaN NaN 625.0 NaN NaN NaN NaN NaN
4 L_0005 NaN NaN NaN 5775.0 NaN NaN NaN NaN NaN
5 L_0006 NaN NaN NaN 495.0 NaN NaN NaN NaN NaN
6 L_0007 NaN NaN NaN 570.0 NaN NaN NaN NaN NaN
7 L_0008 NaN NaN NaN 1250.0 NaN NaN NaN NaN NaN
8 L_0009 NaN NaN NaN NaN NaN NaN 2940.0 P_03_1 1470.0
9 L_0010 NaN NaN NaN NaN NaN NaN 7608.0 P_03_1 7308.0
I think it can be done somehow with merging 2 dataframes after groupby, but I'm not sure how to start. Can you help?
Use modified another solution with pass 2 columns to set_index, last reset ID column and rename it to correct MultiIndex labels, here (Provider, ID):
df = (df.set_index(['ID','Provider'], append=True)
.unstack()
.swaplevel(1, 0, axis=1)
.sort_index(axis=1)
.reset_index(level=1)
.rename_axis((None, None), axis=1)
.rename(columns={'':'ID'})
.rename(columns={'ID':'Provider'}, level=0))
print (df)
Provider P_01 P_02 \
ID Bundle_Cost Bundle_ID Single_Cost Bundle_Cost Bundle_ID
0 L_0001 NaN NaN 1075.0 NaN NaN
1 L_0002 NaN NaN NaN NaN NaN
2 L_0003 NaN NaN NaN NaN NaN
3 L_0004 NaN NaN NaN NaN NaN
4 L_0005 NaN NaN NaN NaN NaN
5 L_0006 NaN NaN NaN NaN NaN
6 L_0007 NaN NaN NaN NaN NaN
7 L_0008 NaN NaN NaN NaN NaN
8 L_0009 NaN NaN NaN NaN NaN
9 L_0010 NaN NaN NaN NaN NaN
P_03
Single_Cost Bundle_Cost Bundle_ID Single_Cost
0 NaN NaN NaN NaN
1 590.0 NaN NaN NaN
2 6900.0 NaN NaN NaN
3 625.0 NaN NaN NaN
4 5775.0 NaN NaN NaN
5 495.0 NaN NaN NaN
6 570.0 NaN NaN NaN
7 1250.0 NaN NaN NaN
8 NaN 1470.0 P_03_1 2940.0
9 NaN 7308.0 P_03_1 7608.0
Another idea is create tuples and assign new columns, here MultiIndex by MultiIndex.from_tuples:
df = (df.set_index(['ID','Provider'], append=True)
.unstack()
.swaplevel(1, 0, axis=1)
.sort_index(axis=1)
.reset_index(level=1)
.rename_axis((None, None), axis=1))
mux = [('Provider', 'ID')] + df.columns.tolist()[1:]
df.columns = pd.MultiIndex.from_tuples(mux)
print (df)
Provider P_01 P_02 \
ID Bundle_Cost Bundle_ID Single_Cost Bundle_Cost Bundle_ID
0 L_0001 NaN NaN 1075.0 NaN NaN
1 L_0002 NaN NaN NaN NaN NaN
2 L_0003 NaN NaN NaN NaN NaN
3 L_0004 NaN NaN NaN NaN NaN
4 L_0005 NaN NaN NaN NaN NaN
5 L_0006 NaN NaN NaN NaN NaN
6 L_0007 NaN NaN NaN NaN NaN
7 L_0008 NaN NaN NaN NaN NaN
8 L_0009 NaN NaN NaN NaN NaN
9 L_0010 NaN NaN NaN NaN NaN
P_03
Single_Cost Bundle_Cost Bundle_ID Single_Cost
0 NaN NaN NaN NaN
1 590.0 NaN NaN NaN
2 6900.0 NaN NaN NaN
3 625.0 NaN NaN NaN
4 5775.0 NaN NaN NaN
5 495.0 NaN NaN NaN
6 570.0 NaN NaN NaN
7 1250.0 NaN NaN NaN
8 NaN 1470.0 P_03_1 2940.0
9 NaN 7308.0 P_03_1 7608.0
Related
Imagine we have a DataFrame created like this:
tmp_df = pd.DataFrame(index=xrange(10), columns=['3-1','3-2'])
tmp_df = pd.concat({'2-1': tmp_df, '2-2': tmp_df},axis=1)
tmp_df = pd.concat({'1-1': tmp_df, '1-2': tmp_df}, axis=1)
Which gives:
1-1 1-2
2-1 2-2 2-1 2-2
3-1 3-2 3-1 3-2 3-1 3-2 3-1 3-2
0 NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN NaN NaN NaN NaN
6 NaN NaN NaN NaN NaN NaN NaN NaN
7 NaN NaN NaN NaN NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN NaN NaN
9 NaN NaN NaN NaN NaN NaN NaN NaN
Thus, we have a three-level column indexed DataFrame. Nonetheless, if we want to concatenate to this a different two-level column indexed DataFrame such as:
tmp2_df = pd.Series(np.nan,index=xrange(10))
tmp2_df = pd.concat({'1-3':pd.concat({'2-1': tmp2_df, '2-2': tmp2_df},axis=1)},axis=1)
1-3
2-1 2-2
0 NaN NaN
1 NaN NaN
2 NaN NaN
3 NaN NaN
4 NaN NaN
5 NaN NaN
6 NaN NaN
7 NaN NaN
8 NaN NaN
9 NaN NaN
Using pd.concat(...) destroys the hierarchy:
pd.concat([tmp_df,tmp2_df],axis=1).columns
Index([(u'1-1', u'2-1', u'3-1'), (u'1-1', u'2-1', u'3-2'),
(u'1-1', u'2-2', u'3-1'), (u'1-1', u'2-2', u'3-2'),
(u'1-2', u'2-1', u'3-1'), (u'1-2', u'2-1', u'3-2'),
(u'1-2', u'2-2', u'3-1'), (u'1-2', u'2-2', u'3-2'),
(u'1-3', u'2-1'), (u'1-3', u'2-2')],
dtype='object')
How can we mantain the column index hierarchy in a way that for tmp2_df there is not a 3rd level of column index? Output should be something like:
1-1 1-2 1-3
2-1 2-2 2-1 2-2 2-1 2-2
3-1 3-2 3-1 3-2 3-1 3-2 3-1 3-2
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
7 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
9 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
I am aware that you can do things like:
tmp_df['test'] = pd.Series(np.nan,index=xrange(10))
1-1 1-2 test
2-1 2-2 2-1 2-2
3-1 3-2 3-1 3-2 3-1 3-2 3-1 3-2
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
5 NaN NaN NaN NaN NaN NaN NaN NaN NaN
6 NaN NaN NaN NaN NaN NaN NaN NaN NaN
7 NaN NaN NaN NaN NaN NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN NaN NaN NaN
9 NaN NaN NaN NaN NaN NaN NaN NaN NaN
But this solution does not work for appending DataFrames:
ValueError: Wrong number of items passed 2, placement implies 1
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
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
Hi I'm trying to subtract values of one of DataFrame columns from whole DataFrame. Intuitively this seems like a non-problem for me, but somehow I can't figure it out.
Here is the code:
import pandas as pd
x = pd.DataFrame({
"a": range(1, 10),
"b": range(2, 11),
"c": range(11, 20)
})
print x - x['b']
And what I get is surprisingly:
0 1 2 3 4 5 6 7 8 a b c
0 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
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
7 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
Instead of DataFrame with columns: (a-b), (b-b), (c-b).
I just started playing with Python. Can you tell me what am I missing?
Thanks!
Try:
x.subtract(x['b'], axis=0)
a b c
0 -1 0 9
1 -1 0 9
2 -1 0 9
3 -1 0 9
4 -1 0 9
5 -1 0 9
6 -1 0 9
7 -1 0 9
8 -1 0 9
See docs for details on the axis=0 parameter, which ensures that the index of x['B'] aligns with the DataFrame index, and not the columns as per default.
To make the - operator work, you'd have to:
(x.T - x['b']).T
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