2015-04-02 3 views
2

Я хотел бы объединить два кадра данных по столбцам Name and Depth. Глубина в левом df имеет один столбец глубины («глубина»). Однако правый df имеет два столбца глубины ('top_depth' и 'bottom_depth').В Pandas слияние двух dataframs со сложным мультииндексированием

Я хотел бы взять каждую запись из левого df и, если доступно, назначить запись справа df, если между «top_depth» и «bottom_depth» находится «глубина».

Я соединил несколько простых dataframes:

df1 = pd.DataFrame(np.array([ 
    ['b1', 4, 9], 
    ['b1', 5, 61], 
    ['b1', 15, 95], 
    ['b1', 24, 9], 
    ['b2', 4, 5], 
    ['b2', 6, 6], 
    ['b2', 44, 0]]), 
    columns=['name', 'depth', 'attr1']) 
df2 = pd.DataFrame(np.array([ 
    ['b1', 1, 6, 66], 
    ['b1', 14, 16, 99], 
    ['b1', 51, 55, 9], 
    ['b3', 0, 5, 32]]), 
    columns=['name', 'top_depth', 'bottom_depth', 'attr2']) 

Тогда сливаются, чтобы получить это:

>>> df3 
    name depth top_depth bottom_depth attr1 attr2 
0 b1 4.0  1.0   6.0 9.0 66.0 
1 b1 5.0  1.0   6.0 61.0 66.0 
2 b1 15.0  14.0   16.0 95.0 99.0 
3 b1 24  NaN   NaN  9 NaN 
4 b2  4  NaN   NaN  5 NaN 
5 b2  6  NaN   NaN  6 NaN 
6 b2 44  NaN   NaN  0 NaN 

Я уверен, что я мог понять, грубой силы подход к этому, но имеет должно быть лучше, больше панд, способ сделать это.

+0

Что случилось с b3 в строке 3 (из df2)? –

+1

Почему df2 ['top_depth'] - df2 ['bottom_depth'] не всегда положительный или отрицательный? –

+0

Лиам вы поймали мою ошибку. Третья строка в df2 (строка 2) должна быть 51, 55, не 55, 51. Я отредактировал свой вопрос. Спасибо. df2 ['bottom_depth'] - df2 ['top_depth'] всегда должен быть положительным. – Todd

ответ

0

Вы можете join (по индексу):

In [11]: df1.join(df2, how='outer', rsuffix='_') 
Out[11]: 
    name depth attr1 name_ top_depth bottom_depth attr2 
0 b1  4  9 b1   1   6 66 
1 b1  5 61 b1  14   16 99 
2 b1 15 95 b1  55   51  9 
3 b1 24  9 b3   0   5 32 
4 b2  4  5 NaN  NaN   NaN NaN 
5 b2  6  6 NaN  NaN   NaN NaN 
6 b2 44  0 NaN  NaN   NaN NaN 

Примечание: rsuffix требуется, так как столбцы имен не совпадают ... это не понятно, что вы хотели бы сделать с этим делом.


Примечание: np.array заставляет массивы разделить (? Парафировать) тип данных, в данном случае это означает, что все числа являются строками. Вы можете передать простой список python в DataFrame!

Вот немного неэффективный метод, сначала функцию, которая определяет имя и проверяет, что глубина находится в пределах верхней и нижней:

def get_depth_group(name, depth): 
    arr = (df2.name == name) & (df2.bottom_depth > depth) & (depth > df2.top_depth) 
    return df2.iloc[arr.argmax()] if any(arr) else np.nan 

Это может быть более эффективным, чтобы использовать другую структуру данных для это ... но это сработает!

In [21]: df1[['depth', 'attr1']].join(df1.apply(lambda x: get_depth_group(x['name'], x['depth']), axis=1)) 
Out[21]: 
    depth attr1 name top_depth bottom_depth attr2 
0  4  9 b1   1    6  66 
1  5  61 b1   1    6  66 
2  15  95 b1   14   16  99 
3  24  9 NaN  NaN   NaN NaN 
4  4  5 NaN  NaN   NaN NaN 
5  6  6 NaN  NaN   NaN NaN 
6  44  0 NaN  NaN   NaN NaN 
+0

Это отлично работает! Спасибо за помощь. – Todd

0

Частичные:

import pandas as pd 
import numpy as np 

df1 = pd.DataFrame(np.array([ 
    ['b1', 4, 9], 
    ['b1', 5, 61], 
    ['b1', 15, 95], 
    ['b1', 24, 9], 
    ['b2', 4, 5], 
    ['b2', 6, 6], 
    ['b2', 44, 0]]), 
    columns=['name', 'depth', 'attr1']) 
df2 = pd.DataFrame(np.array([ 
    ['b1', 1, 6, 66], 
    ['b1', 14, 16, 99], 
    ['b1', 51, 55, 9], 
    ['b3', 0, 5, 32]]), 
    columns=['name', 'top_depth', 'bottom_depth', 'attr2']) 

om = pd.ordered_merge(df2, df1) 
om = om.convert_objects(convert_numeric=True) 
sandwiched = om.query('(depth > top_depth) & (depth <= bottom_depth)') 

зажатый является:

name top_depth bottom_depth attr2 depth attr1 
0 b1   1    6  66  4  9 
1 b1   1    6  66  5  61 
6 b1   14   16  99  15  95 

И я думаю, что вы можете прикрепить остальные df1 с помощью join я не могу вспомнить.

В конце концов, это может быть не проблема в форме SQL. Можете ли вы предположить, что они отсортированы по глубине и top_depth? И перекрываются ли диапазоны df2? Итерация через каждый блок данных однажды может быть эффективным способом.

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