2013-07-14 6 views
2

Есть ли простой способ найти непересекающееся множество записей (что останется на каждом из двух исходных данных, которые не включены в итоговое внутреннее соединение) между двумя базами данных pandas на MultiIndex?Disjoint набор записей из двух pandas DataFrames

Я пропустил что-то довольно очевидное или мне нужно потратить некоторое время на реализацию такого рода функций?

Я попытался сделать это, найдя симметричную разницу между множеством ключей muliIndex двух кадров данных, но это оказалось затруднительным. Я изо всех сил пытаюсь заставить это работать. Моим другим вариантом, который, похоже, может быть немного легче, является добавление фиктивного столбца целых чисел, который может выступать в роли другого отдельного индекса, который сохраняется даже после того, как я делаю слияние multiIndex, поэтому я могу использовать операторы набора python для этот де-факто единственный ключ.

[Обратите внимание, что это связано с, но немного иначе, чем этот вопрос, потому что это слияние не основано на объекте мультииндексных, но по значениям столбцов dataframe: How do I do a SQL style disjoint or set difference on two Pandas DataFrame objects?]

ответ

1

Я думаю, что ваш подход к поиску симметричная разница - путь.

In [97]: from numpy import random 

In [98]: arrays1 = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'], 
    ....:   ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']] 


In [99]: arrays2 = [['bar', 'baz', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'], [ 
    ....: 'one', 'one', 'two', 'three', 'one', 'two', 'one', 'three']] 


In [100]: tuples1 = zip(*arrays1) 

In [101]: tuples2 = zip(*arrays2) 

In [102]: index1 = MultiIndex.from_tuples(tuples1, names=['first', 'second']) 

In [103]: index2 = MultiIndex.from_tuples(tuples2, names=['first', 'second']) 

In [104]: df1 = pd.DataFrame(random.randn(8, 2), index=index1) 

In [105]: df2 = pd.DataFrame(random.randn(8, 2), index=index2) 

In [106]: df1 
Out[106]: 
        0   1 
first second      
bar one  0.613378 -0.400247 
baz one -3.005834 0.004879 
     two  0.066539 -0.289100 
     three -0.020099 0.644226 
foo one -0.461458 -1.621812 
     two  0.286655 0.110588 
qux one  0.363648 -0.271281 
     three 1.707787 -1.832602 

In [107]: df2 
Out[107]: 
        0   1 
first second      
bar one -1.010482 -0.023373 
baz one -0.040335 1.553905 
     two -0.080283 -0.571686 
     three -0.985722 -0.795481 
foo one  0.623122 2.124316 
     two -0.493333 -0.343462 
qux one -1.346753 -1.343945 
     three -0.053497 -0.382402 

In [108]: sym_diff = (df1.index - df2.index).union(df2.index - df1.index) 

In [109]: sym_diff 
Out[109]: 
MultiIndex 
[(u'baz', u'three'), (u'qux', u'three')] 

Я не уверен, почему на MultiIndex не существует метода симметричной разницы.

+0

Хорошо, это работает, когда я меняю строку 103 на index2 и последний член в строке 108 на df1.index. Единственная проблема заключается в том, что MultiIndex и размер моих кадров данных заканчиваются тем, что уходят почти на минуту, чтобы вычислить sym_diff. Я думаю, что ваш путь выглядит более элегантным, но то, что я закончил, было немного другим. Я отклоняю индекс до того, как я слился, а затем дважды слился, сохраняя индекс одного кадра в первый раз, а второй - второй раз. Затем я уронил сопоставленные строки по индексу в каждом из исходных столбцов. Это был скорее код, а больше 5 секунд. –

+0

Я напишу свое решение позже сегодня в случае, если это полезно для всех. –

+0

Извините за опечатки, вы правы на обеих учетных записях. Слишком плохо, мой путь был настолько медленным. Уточняются ли ваши индексы раньше времени? Интересно, занимает ли это больше времени или если это заданные операции. – TomAugspurger

0

Используя те же тестовые данные, как показано на TomAugspurger

import pandas as pd 
import numpy as np 

# create a test data set 
arrays1 = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'], 
      ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']] 
arrays2 = [['bar', 'baz', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'], 
      ['one', 'one', 'two', 'three', 'one', 'two', 'one', 'three']] 
tuples1 = zip(*arrays1) 
tuples2 = zip(*arrays2) 
index1 = pd.MultiIndex.from_tuples(tuples1, names=['first', 'second']) 
index2 = pd.MultiIndex.from_tuples(tuples2, names=['first', 'second']) 
df1 = pd.DataFrame(np.random.randn(8, 2), index=index1) 
df2 = pd.DataFrame(np.random.randn(8, 2), index=index2) 

, который дает следующие две таблицы

     0   1 
first second      
bar one -0.579214 0.261575 
     two  0.912683 -0.475463 
baz one -0.295739 -0.586646 
     two  0.031916 0.199812 
foo one -0.724781 -1.245275 
     two -0.824759 2.270161 
qux one  0.638533 0.537306 
     two -0.988444 -1.076636 

и

     0   1 
first second      
bar one -0.859494 0.214814 
baz one -0.446976 1.281912 
     two -0.181159 0.574126 
     three 0.212799 -1.592317 
foo one -1.192866 1.544799 
     two  1.025816 0.921364 
qux one -0.927700 -0.516720 
     three 0.610065 0.028249 

, то вы можете получить непересекающиеся dataframe по

df1[~df1.index.isin(df2.index)].append(df2[~df2.index.isin(df1.index)]) 

в результате

     0   1 
first second      
bar two  0.912683 -0.475463 
qux two -0.988444 -1.076636 
baz three 0.212799 -1.592317 
qux three 0.610065 0.028249 

Это то, что вы просили?

Смежные вопросы