在pandas python中的VLOOKUP Excel模拟

时间:2016-05-18 12:06:20

标签: python pandas

我有2个dataFrames。

DF1:

index ID City         Region 2City
1     23 Moscow       Msk    
2     34 Obninsk      Msk    Msk
3     56                     Spb
4     17 Tula         Spb

DF2:

index City   Office
1     Msk    Msk
2     Spb    Spb
3     Tula   Msk
4     Moscow Msk

我想获得以下df:

index ID City         Region 2City Office
1     23 Moscow       Msk          Msk
2     34 Obninsk      Msk    Msk   Msk
3     56                     Spb   Spb
4     17 Tula         Spb          Msk

因此,它会检查来自df2的'office'与来自df1的'City''Region''2City'匹配。

如果我找到'office'的{​​{1}},我就会停止搜索。因此,'City'列具有优先权,然后是'City',然后是'Region'

我知道如何使用3 '2City'执行此操作,但我希望有更好的选择。

4 个答案:

答案 0 :(得分:1)

通常使用join(默认为左连接)或merge(必须指定how='left')在Pandas中执行VLOOKUP。

在您的情况下,您尝试基于三列查找值。一种方法是使用or获取第一个非空值。

>>> (df1
     .assign(temp = [region or two_city or city 
                     for region, two_city, city in zip(df1.Region, df1['2City'], df1.City)])
     .merge(df2, how='left', right_on='City', left_on='temp', suffixes=['', '_'])
     .drop(['temp', 'City_'], axis=1))

   ID     City Region 2City Office
0  23   Moscow    Msk  None    Msk
1  34  Obninsk    Msk   Msk    Msk
2  56     None   None   Spb    Spb
3  17     Tula    Spb  None    Msk

答案 1 :(得分:0)

您可以将两个DataFrame合并到pd.merge,但据我了解,您实际上想要合并df1中的不同列。一种可行的方法是添加一个额外的列,如果可用,则使用'City'的值(否则为'region''2City')。

import pandas as pd

df1['Office'] = df1.City.fillna(df1.Region).fillna(df1['2City'])
df = pd.merge(df1, df2.reindex(columns='Office'), on='Office')

您不指定在任一DataFrame中是否缺少值。如果是这样,您可以使用how的{​​{1}}参数控制其处理。

答案 2 :(得分:0)

没有for循环:

cols = ['City', 'Region', '2City']

df1[cols].applymap(lambda x: df2.set_index('City')['Office'].get(x)) \
         .apply(lambda row: row[row.first_valid_index()], axis=1)

我将City设置为df2的索引,以便使用get方法查找值。在使用applymap按元素查找值后,我找到first_valid_index的第一个有效答案。

答案 3 :(得分:0)

import pandas as pd
df1 = pd.DataFrame([[23, 'Moscow', 'Msk', ''],
                    [34, 'Obninsk', 'Msk', 'Msk'],
                    [56, '', '', 'Spb'],
                    [17, 'Tula', 'Spb', '']],
                   columns=['ID', 'City', 'Region', '2City'])
df2 = pd.DataFrame([['Msk', 'Msk'],
                    ['Spb', 'Spb'],
                    ['Tula', 'Msk'],
                    ['Moscow', 'Msk']],
                   columns=['City', 'Office'])

df = pd.concat([df1.loc[df1[x].isin(df2['City']), x] for x in ['City', 'Region', '2City']])
df1['Join'] = df.groupby(df.index).first()
output = df1.merge(df2, left_on='Join', right_on='City', how='right')

此时,名为“output”的pandas.DataFrame将包含一个名为“Office”的列,该列已正确索引以与df1匹配。你可以这样做:

df1['Office'] = output['Office']

这将为您提供所请求的DataFrame以及附加列“Join”,您可以通过以下方式删除:

df1.drop('Join', axis=1, inplace=True)

这里的OP基本上要做三个单独的合并 - 一个在df1的每个列“City”,“Region”和“2City”上。因此,如果没有一些体操,使用基本的pandas.DataFrame操作就不容易做到这一点。我只是隐藏了列表理解中的for循环,但它仍然存在。