如何在两个数据帧之间的np.where中避免NaN?

时间:2019-07-07 22:09:21

标签: python pandas numpy

我有客户数据,并想使用np.where检查他们的电子邮件是否存在于单独的df中,这将返回“匹配”或“不匹配”。

但是,客户电子邮件之一是NaN,而第二个df中的一封电子邮件是nan,因此作为匹配返回。如您所见,找到了一个匹配的先生堆栈溢出匹配项。

customers = pd.DataFrame({'firstname':['stack','Bar Bar','Foo Bar','jim','john','mary','jim'],
                   'lastname':['overflow','Bar','Foo Bar','ryan','con','sullivan','Ryan'],
                   'email':[np.nan,'Bar','Foo Bar','jim@com','john@com','mary@com','Jim@com']})

customers

    firstname   lastname    email
0   jim             bob             NaN
1   Bar Bar     Bar     bar@com
2   Foo Bar     Foo Bar     foo@com
3   jim     ryan        jim@com
4   john        con     john@com
5   mary        sullivan    hello@com
6   jim     Ryan        jon@com

现在,我想检查他们的电子邮件是否在下面称为“电子邮件”的另一个数据框中:


emails = pd.DataFrame({'emails':['mary@com','bar@com','foo@com','jim@com','john@com',np.nan,'jon@com']})

emails

    emails
0   mary@com
1   bar@com
2   foo@com
3   jim@com
4   john@com
5   NaN
6   jon@com

我将创建一个名为“检查”的新列,该列会将检查结果记录为“匹配”或“不匹配”


customers['check'] = np.where(customers['email'].isin(emails['emails']), 'match', 'no_match')

customers


    firstname   lastname    email       check
0   jim     bob     NaN     match
1   Bar Bar     Bar     bar@com     match
2   Foo Bar     Foo Bar     foo@com     match
3   jim     ryan        jim@com     match
4   john        con     john@com    match
5   mary        sullivan    hello@com   no_match
6   jim     Ryan        jon@com     match

除了吉姆·鲍勃的唱片,一切看起来都不错。他的电子邮件是NaN,电子邮件数据框中有一个NaN。因此它作为匹配项返回。

解决这个问题的最佳方法是什么?

我当时正在考虑做一些诸如fillna()之类的事情,并将其更改为诸如'fakeNaN'之类的字符串,所以它没有匹配项。但是必须有更好的方法。

编辑:我刚刚尝试过:

定义了用于lambda的函数,如果客户没有电子邮件,则返回no_email。

def lam(r):

# if the email is nan, return no_email

    if r == np.nan:
        return 'no_email'

    elif r in emails['emails']:
        return 'match'

    elif not r in emails['emails']:
        return 'no_match'

# apply this lambda operation to the customer email row and return results to customer['check']

customers['check'] = customers.apply(lambda row: lam(row['email']), axis=1)

但是,现在所有内容都返回no_match。有一些比赛。

0    no_match
1    no_match
2    no_match
3    no_match
4    no_match
5    no_match
6    no_match
dtype: object

edit2 :我现在发现有些奇怪。

我可以检查emails['emails']并查看其中jim@com

emails['emails']

0    mary@com
1     bar@com
2     foo@com
3     jim@com
4    john@com
5         NaN
6     jon@com
Name: emails, dtype: object

那为什么不起作用?

'jim@com' in emails['emails']

False

2 个答案:

答案 0 :(得分:1)

isinnp.select

m1=customers.email.isin(emails.emails.dropna().values)
m2=customers.email.notna()
customers['check']=np.select([m1&m2,~m1&m2],['match','no match'],default='no_email')
customers
  firstname  lastname     email     check
0     stack  overflow       NaN  no_email        
1   Bar Bar       Bar       Bar  no match
2   Foo Bar   Foo Bar   Foo Bar  no match
3       jim      ryan   jim@com     match
4      john       con  john@com     match
5      mary  sullivan  mary@com     match
6       jim      Ryan   Jim@com  no match

答案 1 :(得分:1)

将电子邮件另存为熊猫系列。稍微不合常规的方法。

*1用于将布尔值转换为整数。

emails = pd.Series(['mary@com','bar@com','foo@com','jim@com','john@com',np.nan,'jon@com'])

(customers['email'].isin(emails)*1+customers['email'].isnull()*1).map({0:'No-Match',1:'Match',2:'No-Record'})

0   No-Record
1   No-Match
2   No-Match
3   Match
4   Match
5   Match
6   No-Match