Pandas如何合并两个带有空值的列?

50

我有一个包含两列的df,我想要合并这两列但忽略NaN值。问题在于有时候这两列都是NaN值,在这种情况下,我希望新列也是NaN。以下是示例:

df = pd.DataFrame({'foodstuff':['apple-martini', 'apple-pie', None, None, None], 'type':[None, None, 'strawberry-tart', 'dessert', None]})

df
Out[10]:
foodstuff   type
0   apple-martini   None
1   apple-pie   None
2   None    strawberry-tart
3   None    dessert
4   None    None

我尝试使用fillna来解决这个问题:

df['foodstuff'].fillna('') + df['type'].fillna('')

然后我得到了:

0      apple-martini
1          apple-pie
2    strawberry-tart
3            dessert
4                   
dtype: object

第四行已成为空值。在这种情况下,我希望得到一个NaN值,因为两个合并列都是NaN。

0      apple-martini
1          apple-pie
2    strawberry-tart
3            dessert
4            None       
dtype: object
8个回答

76

使用fillna函数,将一个列的填充值设置为另一个列:

df['foodstuff'].fillna(df['type'])

生成的输出:

0      apple-martini
1          apple-pie
2    strawberry-tart
3            dessert
4               None

这仅适用于提供了相当不切实际的示例的情况,其中每行始终至少有一个None。 - kilgoretrout
@kilgoretrout 我发现即使两列都包含空值,它也能正常工作。 - jdeng
有没有办法在同一行中使用 fillna 后删除 type 列?即避免另一个 drop 语句。 - sjd
类型错误: "value" 参数必须是标量、字典或序列,但您传递了一个 "Series"。 - Sudip Adhikari

7

您可以使用combine方法和一个lambda来实现:

df['foodstuff'].combine(df['type'], lambda a, b: ((a or "") + (b or "")) or None, None)

(a or "") 如果 a 是 None,则返回 "",同样的逻辑也应用于连接操作(如果连接结果是空字符串,则返回 None)。


4
  • 一起使用fillna填充两个列
  • 使用sum(1)相加
  • 使用replace('', np.nan)替换

df.fillna('').sum(1).replace('', np.nan)

0      apple-martini
1          apple-pie
2    strawberry-tart
3            dessert
4                NaN
dtype: object

3
如果你需要处理包含其他列没有的内容或者反过来,可以使用以下一行代码:
>>> df.rename(columns={'type': 'foodstuff'}).stack().unstack()
         foodstuff
0    apple-martini
1        apple-pie
2  strawberry-tart
3          dessert

如果您有多列数据需要“繁琐”重命名,只要您可以定义~.rename映射,这个解决方案也可以很好地推广。

重命名的目的是创建一些可以供~.stack().unstack()处理的副本。

正如所解释的那样,此解决方案仅适用于具有正交列的配置,即从未同时赋值的列。


1
在我的情况下,pd.DataFrame.stack() 执行列组合。 unstack 则是将它们取消组合。 - Despe1990

2
您可以始终使用None来填充新列中的空字符串。
import numpy as np

df['new_col'].replace(r'^\s*$', np.nan, regex=True, inplace=True)

完整代码:

import pandas as pd
import numpy as np

df = pd.DataFrame({'foodstuff':['apple-martini', 'apple-pie', None, None, None], 'type':[None, None, 'strawberry-tart', 'dessert', None]})

df['new_col'] = df['foodstuff'].fillna('') + df['type'].fillna('')

df['new_col'].replace(r'^\s*$', np.nan, regex=True, inplace=True)

df

输出:

    foodstuff   type    new_col
0   apple-martini   None    apple-martini
1   apple-pie   None    apple-pie
2   None    strawberry-tart strawberry-tart
3   None    dessert dessert
4   None    None    NaN

一个通用的解决方案应该为数值数据类型提供零替换值(.fillna(default_str_or_val))。 - mirekphd

1
使用 combine_first 函数,您可以将一个列中的空值填充为另一个列中的非空值:
In [3]: df['foodstuff'].combine_first(df['type'])
Out[3]: 
0      apple-martini
1          apple-pie
2    strawberry-tart
3            dessert
4               None

0
我们可以让这个问题更完整,并为这种类型的问题提供通用解决方案。
其中关键的事情是,我们希望将一组列连接在一起,但只忽略NaN。
以下是我的答案:
df = pd.DataFrame({'foodstuff':['apple-martini', 'apple-pie', None, None, None], 
               'type':[None, None, 'strawberry-tart', 'dessert', None],
              'type1':[98324, None, None, 'banan', None],
              'type2':[3, None, 'strawberry-tart', np.nan, None]})

enter image description here

df=df.fillna("NAN")
df=df.astype('str')
df["output"] = df[['foodstuff', 'type', 'type1', 'type2']].agg(', '.join, axis=1)
df['output'] = df['output'].str.replace('NAN, ', '')
df['output'] = df['output'].str.replace(', NAN', '')

enter image description here


0

您可以将非零值替换为列名,例如:

df1= df.replace(1, pd.Series(df.columns, df.columns))

接下来,将0替换为空字符串,然后像下面这样合并列:

f = f.replace(0, '')
f['new'] = f.First+f.Second+f.Three+f.Four

请参考下面的完整代码:

import pandas as pd
df = pd.DataFrame({'Second':[0,1,0,0],'First':[1,0,0,0],'Three':[0,0,1,0],'Four':[0,0,0,1], 'cl': ['3D', 'Wireless','Accounting','cisco']})
df2=pd.DataFrame({'pi':['Accounting','cisco','3D','Wireless']})
df1= df.replace(1, pd.Series(df.columns, df.columns))
f = pd.merge(df1,df2,how='right',left_on=['cl'],right_on=['pi'])
f = f.replace(0, '')
f['new'] = f.First+f.Second+f.Three+f.Four

df1:

In [3]: df1                                                                                                                                                                              
Out[3]: 
   Second  First  Three  Four          cl
0       0  First      0     0          3D
1  Second      0      0     0    Wireless
2       0      0  Three     0  Accounting
3       0      0      0  Four       cisco

df2:

In [4]: df2                                                                                                                                                                              
Out[4]: 
           pi
0  Accounting
1       cisco
2          3D
3    Wireless

最终的 DataFrame f 将会是:

In [2]: f                                                                                                                                                                                
Out[2]: 
   Second  First  Three  Four          cl          pi     new
0          First                       3D          3D   First
1  Second                        Wireless    Wireless  Second
2                 Three        Accounting  Accounting   Three
3                        Four       cisco       cisco    Four

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