I want to turn a DataFrame (or a numpy array):
df1:
0 1 2
0 1. 5. 9.
1 2. 6. 10.
2 3. 7. 11.
3 4. 8. 12.
into a DataFrame like this:
df1
0 1 2 3 4 5 6
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN 1. NaN 5. NaN 9. NaN
2 NaN NaN NaN NaN NaN NaN NaN
3 NaN 2. NaN 6. NaN 10. NaN
4 NaN NaN NaN NaN NaN NaN NaN
5 NaN 3. NaN 7. NaN 11. NaN
6 NaN NaN NaN NaN NaN NaN NaN
7 NaN 4. NaN 8. NaN 12. NaN
8 NaN NaN NaN NaN NaN NaN NaN
, i.e., I want to insert NaN rows and columns on df1 (as many as I want)
Could you make this work even for a large DataFrame, where you cannot do this manually?
So far, I have this:
import numpy as np
import pandas as pd
p = np.arange(1,13).reshape(4,3)
p1 = pd.DataFrame(p)
#Add a row of NaN's on p1
p1.index = range(1, 2*len(p1)+1, 2)
p1 = p1.reindex(index=range(2*len(p1)))
#Repeat for rows...I know its a lil bit st*pid
p1 = pd.DataFrame(p1)
p1.index = range(1, 2*len(p1)+1, 2)
p1 = p1.reindex(index=range(2*len(p1)))
#etc...
p1 = pd.DataFrame(p1)
p1.index = range(1, 2*len(p1)+1, 2)
p1 = p1.reindex(index=range(2*len(p1)))
It seems to work, but only for rows until now...
e.g., see this
Based on this answer you can interleave two dataframes on a particular axis.
pd.concat([df1, df2]).sort_index().reset_index(drop=True)
You can start by interleaving by rows (axis=0) df1 with a dataframe containing nan values. And do the same on the columns (axis=1) with another dataframe of nan values.
df1 = pd.DataFrame([[1., 5., 9.], [2., 6., 10.], [3., 7., 11.], [4., 8., 12.]])
rows, cols = df1.shape
Tricky part is getting the sizes right:
nan1 = pd.DataFrame([[np.nan]*cols]*(rows+1))
nan2 = pd.DataFrame([[np.nan]*(cols + 1)]*(2*rows + 1))
Then perform two consecutives concatenations, on axis=0 (default one) and axis=1:
df2_r = pd.concat([nan1, df1]).sort_index().reset_index(drop=True)
df2 = pd.concat([nan2, df2_r], axis=1).sort_index(axis=1).T.reset_index(drop=True).T
Edit: it seems there's is no built-in method to reset the columns indexing. However this will do:
df.T.reset_index(drop=True).T
Here are the results for each operation:
df1
0 1 2
0 1.0 5.0 9.0
1 2.0 6.0 10.0
2 3.0 7.0 11.0
3 4.0 8.0 12.0
nan1
0 1 2
0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN
concat on axis=0
0 1 2
0 NaN NaN NaN
1 1.0 5.0 9.0
2 NaN NaN NaN
3 2.0 6.0 10.0
4 NaN NaN NaN
5 3.0 7.0 11.0
6 NaN NaN NaN
7 4.0 8.0 12.0
8 NaN NaN NaN
nan2
0 1 2 3
0 NaN NaN NaN NaN
1 NaN NaN NaN NaN
2 NaN NaN NaN NaN
3 NaN NaN NaN NaN
4 NaN NaN NaN NaN
5 NaN NaN NaN NaN
6 NaN NaN NaN NaN
7 NaN NaN NaN NaN
8 NaN NaN NaN NaN
concat on axis=1
0 1 2 3 4 5 6
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN 1.0 NaN 5.0 NaN 9.0 NaN
2 NaN NaN NaN NaN NaN NaN NaN
3 NaN 2.0 NaN 6.0 NaN 10.0 NaN
4 NaN NaN NaN NaN NaN NaN NaN
5 NaN 3.0 NaN 7.0 NaN 11.0 NaN
6 NaN NaN NaN NaN NaN NaN NaN
7 NaN 4.0 NaN 8.0 NaN 12.0 NaN
8 NaN NaN NaN NaN NaN NaN NaN
I am curious to see what you have tried so far, but here is an easy "quick and dirty" way to do it for your example. This is not a definitive answer: I'll let you figure out how to generalize it to any dataframe sizes/content you might have.
I am providing this code for your example so you have an idea which pandas functions/properties to use.
import pandas as pd
import numpy as np
# Making your base DataFrame
df = pd.DataFrame([[1,5,9], [2,6,8], [3,7,4]])
df:
0 1 2
0 1 5 9
1 2 6 8
2 3 7 4
spacing out your columns existing columns numbers and adding filling the left columns numbers with NaN:
df.columns = [1,3,5]
for i in range(0, 8, 2):
df[i] = np.NaN
df:
1 3 5 0 2 4 6
0 1 5 9 NaN NaN NaN NaN
1 2 6 8 NaN NaN NaN NaN
2 3 7 4 NaN NaN NaN NaN
Now adding extra rows, with NaN data (we need 4 more with 7 columns)
df2 = pd.DataFrame([[np.NaN] * 7] * 4)
df = pd.concat([df, df2])
df3:
0 1 2 3 4 5 6
0 NaN 1.0 NaN 5.0 NaN 9.0 NaN
1 NaN 2.0 NaN 6.0 NaN 8.0 NaN
2 NaN 3.0 NaN 7.0 NaN 4.0 NaN
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN
As you can see: we have the right data, and it is now only a matter of ordering your rows.
df3.index = [1,3,5,0,2,4,6]
df3 = df3.sort_index()
df3:
0 1 2 3 4 5 6
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN 1.0 NaN 5.0 NaN 9.0 NaN
2 NaN NaN NaN NaN NaN NaN NaN
3 NaN 2.0 NaN 6.0 NaN 8.0 NaN
4 NaN NaN NaN NaN NaN NaN NaN
5 NaN 3.0 NaN 7.0 NaN 4.0 NaN
6 NaN NaN NaN NaN NaN NaN NaN
I think this is a very elegant way to solve this.
array=np.array([[1,5,9],[2,6,10],[3,7,11],[4,8,12]])
Data=pd.DataFrame(array)
Data.index=Data.index*2+1
Data.columns=Data.columns*2+1
Data=Data.reindex(list(range(0,9)))
Data=Data.T.reindex(list(range(0,9)))
A fast way using numpy (work with dataframe as well):
# Sample data
a = np.arange(1,13).reshape(4,3)
df = pd.DataFrame(a)
# New data with empty values
a2 = np.empty([i*2+1 for i in a.shape])
a2[:] = np.nan
a2[1::2, 1::2] = a
Output of pd.DataFrame(a2):
0 1 2 3 4 5 6
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN 1.0 NaN 2.0 NaN 3.0 NaN
2 NaN NaN NaN NaN NaN NaN NaN
3 NaN 4.0 NaN 5.0 NaN 6.0 NaN
4 NaN NaN NaN NaN NaN NaN NaN
5 NaN 7.0 NaN 8.0 NaN 9.0 NaN
6 NaN NaN NaN NaN NaN NaN NaN
7 NaN 10.0 NaN 11.0 NaN 12.0 NaN
8 NaN NaN NaN NaN NaN NaN NaN
Note: If you have a DataFrame, just replace a.shape by df.shape, and a by df.values.
I am working with a pandas dataframe of 15 rows and 8 columns, such a:
A B ... G H
0 0.158979 0.187282 ... 0.330566 0.458748
1 0.227254 0.273307 ... 0.489372 0.649698
2 0.308775 0.351285 ... 0.621399 0.833404
3 0.375850 0.444228 ... 0.759206 0.929980
4 0.431860 0.507906 ... 0.850741 1.038544
5 0.507219 0.596291 ... 0.980404 1.145819
6 0.570170 0.676551 ... 1.094201 1.282077
7 0.635122 0.750434 ... 1.155645 1.292930
8 0.704220 0.824748 ... 1.261516 1.395316
9 0.762619 0.887669 ... 1.337860 1.410864
10 0.824553 0.968889 ... 1.407665 1.437886
11 0.893413 1.045289 ... 1.519902 1.514017
12 0.946757 1.109964 ... 1.561611 1.478634
13 1.008294 1.174139 ... 1.596135 1.501220
14 1.053086 1.227203 ... 1.624630 1.503892
where columns from C to F have been omitted.
I would like to know how I can find the closest value to 1 for every column. Once this value is found I would like to replace the rest of the values in the columns by NaN, with the exception of the values corresponding to the previous and next row. Then obtaining a dataframe like that:
A B ... G H
0 NaN NaN ... NaN NaN
1 NaN NaN ... NaN NaN
2 NaN NaN ... NaN NaN
3 NaN NaN ... NaN 0.929980
4 NaN NaN ... 0.850741 1.038544
5 NaN NaN ... 0.980404 1.145819
6 NaN NaN ... 1.094201 NaN
7 NaN NaN ... NaN NaN
8 NaN NaN ... NaN NaN
9 NaN 0.887669 ... NaN NaN
10 NaN 0.968889 ... NaN NaN
11 NaN 1.045289 ... NaN NaN
12 0.946757 NaN ... NaN NaN
13 1.008294 NaN ... NaN NaN
14 1.053086 NaN ... NaN NaN
Does anyone has a sugestion for this?
Thanks in advance
you can use the fact that the closest to 1 is actually the min of the abs of df once remove 1. So check where the min is meet, use shift once with 1 and once with -1 to get the next and previous row. use this mask in where.
df_ = (df-1).abs()
df_ = df_.min() == df_
df_ = df_|df_.shift(1)|df_.shift(-1)
df_ = df.where(df_)
print(df_)
A B G H
0 NaN NaN NaN NaN
1 NaN NaN NaN NaN
2 NaN NaN NaN NaN
3 NaN NaN NaN 0.929980
4 NaN NaN 0.850741 1.038544
5 NaN NaN 0.980404 1.145819
6 NaN NaN 1.094201 NaN
7 NaN NaN NaN NaN
8 NaN NaN NaN NaN
9 NaN 0.887669 NaN NaN
10 NaN 0.968889 NaN NaN
11 NaN 1.045289 NaN NaN
12 0.946757 NaN NaN NaN
13 1.008294 NaN NaN NaN
14 1.053086 NaN NaN NaN
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
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
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()