0

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

4 Answers4

1

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
Ivan
  • 34,531
  • 8
  • 55
  • 100
0

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
smagnan
  • 1,197
  • 15
  • 29
0

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)))

enter image description here

Dharman
  • 30,962
  • 25
  • 85
  • 135
Hakan Akgün
  • 872
  • 5
  • 13
0

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.

Cainã Max Couto-Silva
  • 4,839
  • 1
  • 11
  • 35