Запрашивание MultiIndex DataFrame в Pandas - PullRequest
0 голосов
/ 18 октября 2018

У меня есть 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 с последним и получить вывод, подобный следующему?

C
59
56
80

Я сделал это путем перебора второго DataFrame, как показано ниже, но я хотел бы сделать это, используя логику панд вместо циклов for.

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

Ответы [ 4 ]

0 голосов
/ 20 октября 2018

Хорошо, я нашел ответ:

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, поэтому их следует отбрасывать.

0 голосов
/ 18 октября 2018

Используйте merge с параметром left_index и right_on:

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

Другое решение с isin из MultiIndex es ифильтрация по 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

Для второго решения инвертируйте маску Boolen с помощью ~:

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
0 голосов
/ 18 октября 2018
FirstDF.loc[zip(SecondDF['A'],SecondDF['B']),]

Объяснение: -

Идея состоит в том, чтобы получить индексы из второго фрейма данных и использовать их в первом фрейме данных.Для мультииндексов вы можете передать набор индексов, чтобы получить строку.

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

даст вам все строки, первый индекс которых равен 'bar, а второй -' two '.

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

берет те индексы непосредственно из SecondDF, которые вы хотите, но выгода заключается в том, что они будут принимать все комбинации «A» и «B».Таким образом, добавление zip займет только индексы, которые являются частью одной строки в SecondDF

0 голосов
/ 18 октября 2018

Вы можете использовать слияние для получения результата;

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...