将2列中的值合并为pandas数据帧中的单个列

Sev*_*yns 33 python numpy dataframe pandas

我正在寻找一种行为类似于在T-SQL中合并的方法.我有两列(A列和B列)在pandas数据帧中稀疏填充.我想使用以下规则创建一个新列:

  1. 如果A列中的值不为null,请将该值用于新列C
  2. 如果A列中的值为null,请使用B列中的值作为新列C

就像我提到的,这可以通过coalesce函数在MS SQL Server中完成.我还没有找到一个好的pythonic方法; 一个存在吗?

Max*_*axU 72

使用combine_first():

In [16]: df = pd.DataFrame(np.random.randint(0, 10, size=(10, 2)), columns=list('ab'))

In [17]: df.loc[::2, 'a'] = np.nan

In [18]: df
Out[18]:
     a  b
0  NaN  0
1  5.0  5
2  NaN  8
3  2.0  8
4  NaN  3
5  9.0  4
6  NaN  7
7  2.0  0
8  NaN  6
9  2.0  5

In [19]: df['c'] = df.a.combine_first(df.b)

In [20]: df
Out[20]:
     a  b    c
0  NaN  0  0.0
1  5.0  5  5.0
2  NaN  8  8.0
3  2.0  8  2.0
4  NaN  3  3.0
5  9.0  4  9.0
6  NaN  7  7.0
7  2.0  0  2.0
8  NaN  6  6.0
9  2.0  5  2.0
Run Code Online (Sandbox Code Playgroud)


Erf*_*fan 23

多列合并 DataFrame.bfill

所有这些方法都适用于两列,并且可能适用于三列,但如果您nn > 2以下情况下有列,则它们都需要方法链接:

示例数据框

import numpy as np
import pandas as pd

df = pd.DataFrame({'col1':[np.NaN, 2, 4, 5, np.NaN],
                   'col2':[np.NaN, 5, 1, 0, np.NaN],
                   'col3':[2, np.NaN, 9, 1, np.NaN],
                   'col4':[np.NaN, 10, 11, 4, 8]})

print(df)

   col1  col2  col3  col4
0   NaN   NaN   2.0   NaN
1   2.0   5.0   NaN  10.0
2   4.0   1.0   9.0  11.0
3   5.0   0.0   1.0   4.0
4   NaN   NaN   NaN   8.0
Run Code Online (Sandbox Code Playgroud)

使用DataFrame.bfill索引轴 ( axis=1),即使对于n大量列,我们也可以以通用方式获取值

另外,这也适用于string type列!

df['coalesce'] = df.bfill(axis=1).iloc[:, 0]

   col1  col2  col3  col4  coalesce
0   NaN   NaN   2.0   NaN       2.0
1   2.0   5.0   NaN  10.0       2.0
2   4.0   1.0   9.0  11.0       4.0
3   5.0   0.0   1.0   4.0       5.0
4   NaN   NaN   NaN   8.0       8.0
Run Code Online (Sandbox Code Playgroud)

使用Series.combine_first(接受的答案),它可能会变得非常麻烦,并且最终会在列数量增加时撤消

df['coalesce'] = (
    df['col1'].combine_first(df['col2'])
        .combine_first(df['col3'])
        .combine_first(df['col4'])
)

   col1  col2  col3  col4  coalesce
0   NaN   NaN   2.0   NaN       2.0
1   2.0   5.0   NaN  10.0       2.0
2   4.0   1.0   9.0  11.0       4.0
3   5.0   0.0   1.0   4.0       5.0
4   NaN   NaN   NaN   8.0       8.0
Run Code Online (Sandbox Code Playgroud)

  • 如果您需要按特定列顺序进行合并,只需选择您需要的列,如`df['coalesce'] = df[['col4', 'col1', 'col2', 'col3']].bfill(axis =1).iloc[:, 0]` (4认同)

Mer*_*lin 12

试试这个..更容易记住:

df['c'] = np.where(df["a"].isnull(), df["b"], df["a"] )
Run Code Online (Sandbox Code Playgroud)

这稍快一些: df['c'] = np.where(df["a"].isnull() == True, df["b"], df["a"] )

%timeit df['d'] = df.a.combine_first(df.b)
1000 loops, best of 3: 472 µs per loop


%timeit  df['c'] = np.where(df["a"].isnull(), df["b"], df["a"] )
1000 loops, best of 3: 291 µs per loop
Run Code Online (Sandbox Code Playgroud)

  • 我想知道为什么添加显式的 `== True` 会使速度更快?!?感觉违反直觉。(但我正在学习不要尝试和直觉_任何事情_与熊猫有关......) (4认同)

cs9*_*s95 10

combine_first是最直接的选择.我在下面概述了其他几个.我将概述一些解决方案,一些适用于不同的情况.

案例#1:非互斥的NaN

并非所有的行具有NaN的,而这些NaNs为互相列之间的排斥.

建立

df = pd.DataFrame({
    'a': [1.0, 2.0, 3.0, np.nan, 5.0, 7.0, np.nan],
    'b': [5.0, 3.0, np.nan, 4.0, np.nan, 6.0, 7.0]})      
df

     a    b
0  1.0  5.0
1  2.0  3.0
2  3.0  NaN
3  NaN  4.0
4  5.0  NaN
5  7.0  6.0
6  NaN  7.0
Run Code Online (Sandbox Code Playgroud)

让我们先结合起来a.

Series.mask

df['a'].mask(pd.isnull, df['b'])
# df['a'].mask(df['a'].isnull(), df['b'])
Run Code Online (Sandbox Code Playgroud)

要么,

0    1.0
1    2.0
2    3.0
3    4.0
4    5.0
5    7.0
6    7.0
Name: a, dtype: float64
Run Code Online (Sandbox Code Playgroud)
df['a'].where(pd.notnull, df['b'])

0    1.0
1    2.0
2    3.0
3    4.0
4    5.0
5    7.0
6    7.0
Name: a, dtype: float64
Run Code Online (Sandbox Code Playgroud)

Series.where

df = pd.DataFrame({
    'a': [1.0, 2.0, 3.0, np.nan, 5.0, np.nan, np.nan],
    'b': [np.nan, np.nan, np.nan, 4.0, np.nan, 6.0, 7.0]})
df

     a    b
0  1.0  NaN
1  2.0  NaN
2  3.0  NaN
3  NaN  4.0
4  5.0  NaN
5  NaN  6.0
6  NaN  7.0
Run Code Online (Sandbox Code Playgroud)

您可以使用类似的语法np.where.

或者,首先组合b,切换条件.


案例#2:互斥的定位NaNs

所有行都具有NaN在列之间互斥的s.

建立

df['b'].update(df['a'])
# Or, to update "a" in-place,
# df['a'].update(df['b'])
df

     a    b
0  1.0  1.0
1  2.0  2.0
2  3.0  3.0
3  NaN  4.0
4  5.0  5.0
5  NaN  6.0
6  NaN  7.0
Run Code Online (Sandbox Code Playgroud)

Series.update

此方法就地工作,修改原始DataFrame.这是此用例的有效选项.

df['a'].add(df['b'], fill_value=0)

0    1.0
1    2.0
2    3.0
3    4.0
4    5.0
5    6.0
6    7.0
dtype: float64
Run Code Online (Sandbox Code Playgroud)

Series.add

df.fillna(0).sum(1)

0    1.0
1    2.0
2    3.0
3    4.0
4    5.0
5    6.0
6    7.0
dtype: float64
Run Code Online (Sandbox Code Playgroud)

DataFrame.fillna+ DataFrame.sum.

df = pd.DataFrame({
    'a': [1.0, 2.0, 3.0, np.nan, 5.0, 7.0, np.nan],
    'b': [5.0, 3.0, np.nan, 4.0, np.nan, 6.0, 7.0]})      
df

     a    b
0  1.0  5.0
1  2.0  3.0
2  3.0  NaN
3  NaN  4.0
4  5.0  NaN
5  7.0  6.0
6  NaN  7.0
Run Code Online (Sandbox Code Playgroud)