使用pandas合并带有缺失值的字符串列

7

我需要将pandas数据框中的2个或多个列中的字符串连接起来。

我找到了这个答案,如果没有任何缺失值,它就能很好地工作。不幸的是,我的情况并非如此,这导致出现像“ValueA;None”这样不太干净的东西。

示例数据:

col_A  | col_B
------ | ------
val_A  | val_B 
None   | val_B 
val_A  | None 
None   | None

我需要这个结果:
col_merge
---------
val_A;val_B
val_B
val_A
None

2
你尝试过在 col_b 上使用空字符串 '' 的 fillna 吗? - Quickbeam2k1
刚刚做了,但是如果第一列中有NaN,我会得到";val_B"。如果两列都有NaN,我只会得到";"。 - CoMartel
1个回答

14
您可以使用if-elseapply结合使用:
df = df.apply(lambda x: None if x.isnull().all() else ';'.join(x.dropna()), axis=1)
print (df)
0    val_A;val_B
1          val_B
2          val_A
3           None
dtype: object

为了更快速的解决方案,可以采取以下措施:

#add separator and replace NaN to empty space
#convert to lists
arr = df.add('; ').fillna('').values.tolist()
#list comprehension, replace empty spaces to NaN
s = pd.Series([''.join(x).strip('; ') for x in arr]).replace('^$', np.nan, regex=True)
#replace NaN to None
s = s.where(s.notnull(), None)
print (s)
0    val_A;val_B
1          val_B
2          val_A
3           None
dtype: object

#40000 rows
df = pd.concat([df]*10000).reset_index(drop=True)

In [70]: %%timeit
    ...: arr = df.add('; ').fillna('').values.tolist()
    ...: s = pd.Series([''.join(x).strip('; ') for x in arr]).replace('^$', np.nan, regex=True)
    ...: s.where(s.notnull(), None)
    ...: 
10 loops, best of 3: 74 ms per loop


In [71]: %%timeit
    ...: df.apply(lambda x: None if x.isnull().all() else ';'.join(x.dropna()), axis=1)
    ...: 
1 loop, best of 3: 12.7 s per loop

#another solution, but slowier a bit
In [72]: %%timeit
     ...: arr = df.add('; ').fillna('').values  
     ...: s = [''.join(x).strip('; ') for x in arr]
     ...: pd.Series([y if y != '' else None for y in s])
     ...: 
     ...: 
10 loops, best of 3: 119 ms per loop

一个令人惊讶的难题,你给出了一个很好的答案。.join().cat() 在这里都出乎意料地失败了。 - johnDanger
我不确定原因何在,但是我找到的所有解决方案,包括最佳解决方案,在 col_B 为空时总是给我一个分隔符,比如“;”。这个“更快”的方案是我找到的唯一一种用分隔符连接值并处理第二列中的 np.nans 的方法。再次感谢 Jazrael 先生! - DrWhat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接