2

Data:

   A    B
0  a    d
1  b  NaN
2  c    c
3  d    f

How might I interleave 0-columns between A and B? I'd like to get:

   A  X    B
0  a  0    d
1  b  0  NaN
2  c  0    c
3  d  0    f

Similarly, for this:

   A    B   C
0  a    d   e
1  b  NaN   a
2  c    c   f
3  d    f   g

I'd like:

   A  X    B    X    C
0  a  0    d    0    e
1  b  0  NaN    0    a
2  c  0    c    0    f
3  d  0    f    0    g

How can I do this?

You can find my attempt at this below. I'd like to know other, possibly shorter/more efficient/eccentric ways of doing this.

cs95
  • 379,657
  • 97
  • 704
  • 746

3 Answers3

4

1) One way to construct columns

In [916]: df.reindex(columns=sum([[c, 'X'] for c in df.columns], [])[:-1], fill_value=0)
Out[916]:
   A  X    B  X  C
0  a  0    d  0  e
1  b  0  NaN  0  a
2  c  0    c  0  f
3  d  0    f  0  g

In [917]: sum([[c, 'X'] for c in df.columns], [])[:-1]
Out[917]: ['A', 'X', 'B', 'X', 'C']

2) Another way to construct

In [924]: def mixcols(cols):
     ...:     ncols = ['X'] * 2 * len(cols)
     ...:     ncols[0::2] = cols
     ...:     return ncols[:-1]

In [925]: mixcols(df.columns)
Out[925]: ['A', 'X', 'B', 'X', 'C']

In [926]: df.reindex(columns=mixcols(df.columns), fill_value=0)
Out[926]:
   A  X    B  X  C
0  a  0    d  0  e
1  b  0  NaN  0  a
2  c  0    c  0  f
3  d  0    f  0  g

3) Inspired from @piR

In [944]: [c for cx in zip(df.columns, ['X']*len(df.columns)*2) for c in cx][:-1]
Out[944]: ['A', 'X', 'B', 'X', 'C']

Also,

In [939]: from itertools import chain, izip

In [940]: list(chain.from_iterable(izip(df.columns, ['X']*len(df.columns)*2)))[:-1]
Out[940]: ['A', 'X', 'B', 'X', 'C']

4) Not recommended way

In [935]: '-|-X-|-'.join(df.columns).split('-|-')
Out[935]: ['A', 'X', 'B', 'X', 'C']
Zero
  • 74,117
  • 18
  • 147
  • 154
3

Option 0

df.reindex_axis([x for y in lst for x in [y, 'X']][:-1], 1, fill_value=0)

   A  X    B  X  C
0  a  0    d  0  e
1  b  0  NaN  0  a
2  c  0    c  0  f
3  d  0    f  0  g

Option 1
String hackery
Actually, @John Galt beat me to this one.

df.reindex_axis('|X|'.join(df).split('|'), 1, fill_value=0)

   A  X    B  X  C
0  a  0    d  0  e
1  b  0  NaN  0  a
2  c  0    c  0  f
3  d  0    f  0  g

Option 2
Use cytoolz.interleave
Learned from @root here

from cytoolz import interleave

df.reindex(
    columns=list(interleave([df, list('X' * (df.shape[1] - 1))])),
    fill_value=0)

   A  X    B  X  C
0  a  0    d  0  e
1  b  0  NaN  0  a
2  c  0    c  0  f
3  d  0    f  0  g
piRSquared
  • 285,575
  • 57
  • 475
  • 624
1

My attempt at a solution with df.reindex:

def foo(cols):
     yield cols[0]
     for c in cols[1:]:
         yield from ('X', c)

df1.reindex(columns=foo(df1.columns), fill_value=0)

   A  X    B
0  a  0    d
1  b  0  NaN
2  c  0    c
3  d  0    f
cs95
  • 379,657
  • 97
  • 704
  • 746