在熊猫中查询MultiIndex DataFrame

时间:2018-10-18 06:05:44

标签: python pandas

我有一个看起来像这样的DataFrame:

FirstDF=
              C
A    B      
'a' 'blue'   43
    'green'  59
'b' 'red     56
'c' 'green'  80
    'orange' 72

其中A和B设置为索引。我也有一个看起来像这样的DataFrame:

SecondDF=

    A     B
0  'a'  'green'
1  'b'  'red'
2  'c'  'green'

有没有一种方法可以直接查询第一个DataFrame和最后一个DataFrame,并获得如下所示的输出?

C
59
56
80

我通过遍历第二个DataFrame来做到这一点,如下所示,但是我想使用pandas逻辑而不是for循环来实现。

data=[]
for i in range(SecondDF.shape[0]):
    data.append(FirstDF.loc[tuple(SecondDF.iloc[i])])
data=pd.Series(data)

4 个答案:

答案 0 :(得分:2)

merge与参数left_indexright_on一起使用:

df = FirstDF.merge(SecondDF, left_index=True, right_on=['A','B'])['C'].to_frame()
print (df)
    C
0  59
1  56
2  80

另一个isinMultiIndex中并通过boolean indexing进行过滤的解决方案:

mask = FirstDF.index.isin(SecondDF.set_index(['A','B']).index)
#alternative solution
#mask = FirstDF.index.isin(list(map(tuple,SecondDF[['A','B']].values.tolist())))
df = FirstDF.loc[mask, ['C']].reset_index(drop=True)
print (df)
    C
0  59
1  56
2  80

详细信息

print (FirstDF.loc[mask, ['C']])
              C
A   B          
'a' 'green'  59
'b' 'red'    56
'c' 'green'  80

编辑:

您可以将merge与外部联接和indicator=True参数一起使用,然后按boolean indexing进行过滤:

df1=FirstDF.merge(SecondDF, left_index=True, right_on=['A','B'], indicator=True, how='outer')
print (df1)
    C    A         B     _merge
2  43  'a'    'blue'  left_only
0  59  'a'   'green'       both
1  56  'b'     'red'       both
2  80  'c'   'green'       both
2  72  'c'  'orange'  left_only

mask = df1['_merge'] != 'both'
df1 = df1.loc[mask, ['C']].reset_index(drop=True)
print (df1)
    C
0  43
1  72

对于第二个解决方案,用~反转布尔值掩码:

mask = FirstDF.index.isin(SecondDF.set_index(['A','B']).index)
#alternative solution
#mask = FirstDF.index.isin(list(map(tuple,SecondDF[['A','B']].values.tolist())))
df = FirstDF.loc[~mask, ['C']].reset_index(drop=True)
print (df)
    C
0  43
1  72

答案 1 :(得分:2)

FirstDF.loc[zip(SecondDF['A'],SecondDF['B']),]

说明:-

想法是从第二个数据帧中获取索引,并在第一个数据帧上使用它们。 对于多索引,您可以传递索引的元组来获取行。

FirstDF.loc[('bar','two'),] 

将为您提供所有第一个索引为'bar并且第二个索引为'two'的行。

FirstDF.loc[(SecondDF['A'],SecondDF['B']),] 

直接从SecondDF中获取您想要的那些索引,但是要注意的是它将获取'A'和'B'的所有组合。因此,添加zip将仅使用SecondDF同一行中一部分的索引

答案 2 :(得分:0)

您可以使用merge获得结果;

In [35]: df1
Out[35]:
   A       B   C
0  a    blue  43
1  a   green  59
2  b     red  56
3  c   green  80
4  c  orange  72

In [36]: df2
Out[36]:
   A      B
0  a  green
1  b    red
2  c  green

In [37]: pd.merge(df1, df2, on=['A', 'B'])['C']
Out[37]:
0    59
1    56
2    80
Name: C, dtype: int64

答案 3 :(得分:0)

好的,我找到了答案:

tuple_list = list(map(tuple,SecondDF.values))
insDF = FirstDF.loc[tuple_list].dropna()
outsDF = FirstDF.loc[~FirstDF.index.isin(tuple_list)]

这将提供FirstDF中的值和非值。 之所以使用dropna方法,是因为该查询将SecondDF中不在FirstDF中的值留为NaN,因此应将其删除。