pandas 将两列与空值组合在一起

问题描述 投票:0回答:9

我有一个包含两列的 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

第 4 行已成为空白值。在这种情况下我想要的是 NaN 值,因为两个组合列都是 NaN。

0      apple-martini
1          apple-pie
2    strawberry-tart
3            dessert
4            None       
dtype: object
python pandas dataframe nonetype
9个回答
80
投票

在一列上使用

fillna
,填充值是另一列:

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

结果输出:

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

7
投票

您可以使用

combine
方法和
lambda
:

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

(a or "")

,则
""
返回
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()
将为您处理。

正如所解释的,该解决方案仅适合正交列的配置,即永远不会同时赋值的列。


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

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
s。

这是我的回答:

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]})

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', '')


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

最终数据框

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

0
投票

如果您使用 NaN 来初始化 DataFrame 来获取缺失值而不是 None,则可以使用 Series.add() 在将列添加在一起时动态填充 NaN 值。

示例:

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

df['foodstuff'].add(df['type'], fill_value = '')

结果:

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

这对于添加具有一些 NaN 值的数字列也非常有效,因为它允许您将数字添加到 NaN 值并获取数字。示例:

df_test_nums = pd.DataFrame({'left_numbers':[1, 1, np.NaN, 3.7, 2.4], 
'right_numbers':[4, np.NaN, np.NaN, 2.7, 9.4]})
print(df_test_nums)

结果:

   left_numbers  right_numbers
0           1.0            4.0
1           1.0            NaN
2           NaN            NaN
3           3.7            2.7
4           2.4            9.4

将这些列加在一起,使数字与 NaN 值的总和就是数字:

df_test_nums['left_numbers'].add(
    df_test_nums['right_numbers'], fill_value = 0)

结果:

0     5.0
1     1.0
2     NaN
3     6.4
4    11.8

将此与 + 运算符的使用进行比较,该运算符将 NaN 与数字之和转换为 NaN:

df_test_nums['left_numbers'] + df_test_nums['right_numbers']

结果:

0     5.0
1     NaN
2     NaN
3     6.4
4    11.8

对于涉及多列的操作,可以通过

df.sum()
获得更优雅的方法。

print(df_test_nums[
          ['left_numbers', 'right_numbers']].sum(
              axis=1, min_count = 1))

输出:

0     5.0
1     1.0
2     NaN
3     6.4
4    11.8

请注意,如果 min_count 设置为 0(默认值),则第三行将等于 0,因为这是仅由 NaN 组成的值相加在一起时的默认输出。 (有关更多信息,请参阅 df.sum() 文档。)

© www.soinside.com 2019 - 2024. All rights reserved.