如何根据条件从多个列中选择值

时间:2020-09-15 07:16:03

标签: python-3.x pandas numpy

我有一个数据框,其中包含有关不同帐户中处于平衡状态的人的信息。看起来像下面的样子。

import pandas as pd
import numpy as np

df = pd.DataFrame({'name':['John', 'Jacob', 'Mary', 'Sue', 'Harry', 'Clara'],
                   'accnt_1':[2, np.nan, 13, np.nan, np.nan, np.nan],
                   'accnt_2':[32, np.nan, 12, 21, 32, np.nan],
                   'accnt_3':[11,21,np.nan,np.nan,2,np.nan]})
df

enter image description here

我想获得每个人的余额,好像accnt_1不为空,即该人的余额。如果accnt_1为空而accnt_2不为空,则accnt_2中的数字为余额。如果accnt_1和accnt_2均为空,则accnt_3中的余额为余额。 最后,输出应类似于

out_df = pd.DataFrame({'name':['John', 'Jacob', 'Mary', 'Sue', 'Harry', 'Clara'],
                  'balance':[2, 21, 13, 21, 32, np.nan]})
out_df

enter image description here

我将永远知道列的优先级。我可以编写一个简单的函数并将其应用于此数据框。但是我在想使用pandas / numpy有更好,更快的方法吗?

3 个答案:

答案 0 :(得分:0)

如果平衡意味着name之后首先不丢失值,则可以将name转换为索引,然后回填丢失的值并按位置选择第一列:

df = df.set_index('name').bfill(axis=1).iloc[:, 0].rename('balance').reset_index()
print (df)
    name  balance
0   John      2.0
1  Jacob     21.0
2   Mary     13.0
3    Sue     21.0
4  Harry     32.0
5  Clara      NaN

如果需要按列表顺序指定列名称:

cols = ['accnt_1','accnt_2','accnt_3']
df = df.set_index('name')[cols].bfill(axis=1).iloc[:, 0].rename('balance').reset_index()

或者如果只需要过滤accnt列,则使用DataFrame.filter

df = df.set_index('name').filter(like='accnt').bfill(axis=1).iloc[:, 0].rename('balance').reset_index()

答案 1 :(得分:0)

您可以简单地将fillna方法彼此链接以实现所需的结果。链接可以用简明英语阅读:“取accnt_1中的值,用accnt_2中的值填充accnt_1中的缺失值。然后,如果此后仍剩余NaN,则用accnt_3中的值填充那些缺失值” < / p>

>>> df["balance"] = df["accnt_1"].fillna(df["accnt_2"]).fillna(df["accnt_3"])
>>> df[["name", "balance"]]
    name  balance
0  John   2.0    
1  Jacob  21.0   
2  Mary   13.0   
3  Sue    21.0   
4  Harry  32.0   
5  Clara  NaN

答案 2 :(得分:0)

df['balance']=df.name.map(df.set_index('name').stack().groupby('name').first())



   name  accnt_1  accnt_2  accnt_3  balance
0   John      2.0     32.0     11.0      2.0
1  Jacob      NaN      NaN     21.0     21.0
2   Mary     13.0     12.0      NaN     13.0
3    Sue      NaN     21.0      NaN     21.0
4  Harry      NaN     32.0      2.0     32.0
5  Clara      NaN      NaN      NaN      NaN

工作方式

#setting name as index gives you an opportunity to get it as a column name when you unstack

df.set_index('name').stack().groupby('name').first()

name          
John   accnt_1     2.0
       accnt_2    32.0
       accnt_3    11.0
Jacob  accnt_3    21.0
Mary   accnt_1    13.0
       accnt_2    12.0
Sue    accnt_2    21.0
Harry  accnt_2    32.0
       accnt_3     2.0
dtype: float64

#Chaining .first() gets you the first index value that is non NaN because when you stack NaN is dropped

df.set_index('name').stack().groupby('name').first()

#.map() allows you to map output above to the original dataframe

df.name.map(df.set_index('name').stack().groupby('name').first())

0     2.0
1    21.0
2    13.0
3    21.0
4    32.0
5     NaN