Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fill in same amount of characters where other column is NaN

I have the following dummy dataframe:

df = pd.DataFrame({'Col1':['a,b,c,d', 'e,f,g,h', 'i,j,k,l,m'],
                   'Col2':['aa~bb~cc~dd', np.NaN, 'ii~jj~kk~ll~mm']})

        Col1            Col2
0    a,b,c,d     aa~bb~cc~dd
1    e,f,g,h             NaN
2  i,j,k,l,m  ii~jj~kk~ll~mm

The real dataset has shape 500000, 90.

I need to unnest these values to rows and I'm using the new explode method for this, which works fine.

The problem is the NaN, these will cause unequal lengths after the explode, so I need to fill in the same amount of delimiters as the filled values. In this case ~~~ since row 1 has three comma's.


expected output

        Col1            Col2
0    a,b,c,d     aa~bb~cc~dd
1    e,f,g,h             ~~~
2  i,j,k,l,m  ii~jj~kk~ll~mm

Attempt 1:

df['Col2'].fillna(df['Col1'].str.count(',')*'~')

Attempt 2:

np.where(df['Col2'].isna(), df['Col1'].str.count(',')*'~', df['Col2'])

This works, but I feel like there's an easier method for this:

characters = df['Col1'].str.replace('\w', '').str.replace(',', '~')
df['Col2'] = df['Col2'].fillna(characters)

print(df)

        Col1            Col2
0    a,b,c,d     aa~bb~cc~dd
1    e,f,g,h             ~~~
2  i,j,k,l,m  ii~jj~kk~ll~mm

d1 = df.assign(Col1=df['Col1'].str.split(',')).explode('Col1')[['Col1']]
d2 = df.assign(Col2=df['Col2'].str.split('~')).explode('Col2')[['Col2']]

final = pd.concat([d1,d2], axis=1)
print(final)

  Col1 Col2
0    a   aa
0    b   bb
0    c   cc
0    d   dd
1    e     
1    f     
1    g     
1    h     
2    i   ii
2    j   jj
2    k   kk
2    l   ll
2    m   mm

Question: is there an easier and more generalized method for this? Or is my method fine as is.

like image 622
Erfan Avatar asked Sep 03 '19 15:09

Erfan


People also ask

How do I fill NaN values in a column?

fillna() method is used to fill NaN/NA values on a specified column or on an entire DataaFrame with any given value. You can specify modify using inplace, or limit how many filling to perform or choose an axis whether to fill on rows/column etc. The Below example fills all NaN values with None value.

How do I fill NaN values in multiple columns?

We can use fillna() function to impute the missing values of a data frame to every column defined by a dictionary of values. The limitation of this method is that we can only use constant values to be filled.

How do you fill a string with NaN values?

We can replace the NaN with an empty string using df. replace() function. This function will replace an empty string inplace of the NaN value.


3 Answers

pd.concat

delims = {'Col1': ',', 'Col2': '~'}
pd.concat({
    k: df[k].str.split(delims[k], expand=True)
    for k in df}, axis=1
).stack()

    Col1 Col2
0 0    a   aa
  1    b   bb
  2    c   cc
  3    d   dd
1 0    e  NaN
  1    f  NaN
  2    g  NaN
  3    h  NaN
2 0    i   ii
  1    j   jj
  2    k   kk
  3    l   ll
  4    m   mm

This loops on columns in df. It may be wiser to loop on keys in the delims dictionary.

delims = {'Col1': ',', 'Col2': '~'}
pd.concat({
    k: df[k].str.split(delims[k], expand=True)
    for k in delims}, axis=1
).stack()

Same thing, different look

delims = {'Col1': ',', 'Col2': '~'}
def f(c): return df[c].str.split(delims[c], expand=True)
pd.concat(map(f, delims), keys=delims, axis=1).stack()
like image 73
piRSquared Avatar answered Sep 18 '22 15:09

piRSquared


One way is using str.repeat and fillna() not sure how efficient this is though:

df.Col2.fillna(pd.Series(['~']*len(df)).str.repeat(df.Col1.str.count(',')))

0       aa~bb~cc~dd
1               ~~~
2    ii~jj~kk~ll~mm
Name: Col2, dtype: object
like image 44
anky Avatar answered Sep 17 '22 15:09

anky


Just split the dataframe into two

df1=df.dropna()
df2=df.drop(df1.index)

d1 = df1['Col1'].str.split(',').explode()
d2 = df1['Col2'].str.split('~').explode()
d3 = df2['Col1'].str.split(',').explode()

final = pd.concat([d1, d2], axis=1).append(d3.to_frame(),sort=False)
Out[77]: 
  Col1 Col2
0    a   aa
0    b   bb
0    c   cc
0    d   dd
2    i   ii
2    j   jj
2    k   kk
2    l   ll
2    m   mm
1    e  NaN
1    f  NaN
1    g  NaN
1    h  NaN
like image 30
BENY Avatar answered Sep 18 '22 15:09

BENY