sjb123
sjb123

Reputation: 53

Shift rows to left

I have a pandas df:

   A   B  C
1 10   11 23
2 NaN  2  15
3 NaN  3  31
4 NaN NaN 56 

I want to shift the rows to the left to line up on the index as below:

  A   B   C
1 10  11  23
2 2   15  NaN
3 3   31  NaN
4 56  NaN NaN

I have been trying to write a function that I can apply to the rows of the df. I was thinking if nan_counts = row.isnull().count() I could use shift(-Nan_counts,axis=1) but I am having absolutely no luck.

Upvotes: 0

Views: 1594

Answers (2)

jezrael
jezrael

Reputation: 862511

Use apply with axis=1 for row processing with dropna:

df = df.apply(lambda x: pd.Series(x.dropna().values), 1)
print (df)
      0     1     2
1  10.0  11.0  23.0
2   2.0  15.0   NaN
3   3.0  31.0   NaN
4  56.0   NaN   NaN

For columns names (general solution):

print (df)
      A     B   C   D   E
1  10.0  11.0  23 NaN NaN
2   NaN   2.0  15 NaN NaN
3   NaN   3.0  31 NaN NaN
4   NaN   NaN  56 NaN NaN

df1 = df.apply(lambda x: pd.Series(x.dropna().values), 1)
df1.columns = df.columns[:len(df1.columns)]
df1 = df1.reindex(df.columns, axis=1)
print (df1)
      A     B     C   D   E
1  10.0  11.0  23.0 NaN NaN
2   2.0  15.0   NaN NaN NaN
3   3.0  31.0   NaN NaN NaN
4  56.0   NaN   NaN NaN NaN

Upvotes: 4

Allen Qin
Allen Qin

Reputation: 19947

For each row, use a list comprehension to keep only non-nan values and convert it as a Series. Pandas will automatically fill missing values with nan when the Serieses are combined.

df.apply(lambda x: pd.Series([e for e in x if pd.notnull(e)]), axis=1)
Out[27]: 
      0     1     2
1  10.0  11.0  23.0
2   2.0  15.0   NaN
3   3.0  31.0   NaN
4  56.0   NaN   NaN

Upvotes: 1

Related Questions