2015-09-30 2 views
2

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

Вот Exemple из dataframes:

df1 = pd.DataFrame(np.array([ 
    ['a', 27, 29, 10], 
    ['a', 29, 30, 2.5], 
    ['a', 30, 32.5, 56], 
    ['a', 32.5, 36, 18], 
    ['a', 36, 39, 5], 
    ['b', 0, 3, 0.5], 
    ['b', 3, 6, 1.5], 
    ['b', 6, 9, 2.5]]), 
    columns=['name', 'top_depth', 'bottom_depth', 'attr1']) 

df2 = pd.DataFrame(np.array([ 
    ['a', 0, 25, 'alpha'], 
    ['a', 25, 28, 'beta'], 
    ['a', 28, 39, 'gamma'], 
    ['b', 0, 6, 'alpha'], 
    ['b', 6, 9, 'beta'], 
    ['b', 9, 18, 'phi'], 
    ['b', 18, 25, 'teta']]), 
    columns=['name', 'top_depth', 'bottom_depth', 'attr2']) 

Затем слить, чтобы получить это:

>>> df3 
    name top_depth bottom_depth attr1 attr2 
0  a   0   25 NaN alpha 
1  a  25   27 NaN beta 
2  a  27   28 10 beta 
2  a  28   29 10 gamma 
3  a  29   30 2.5 gamma 
4  a  30   32.5 56 gamma 
5  a  32.5   36 18 gamma 
6  a  36   39  5 gamma 
7  b   0   3 0.5 alpha 
8  b   3   6 1.5 alpha 
9  b   6   9 2.5 beta 
10 b   9   18 NaN  phi 
11 b  18   25 NaN teta 

Есть простой способ сделать это в панд?

ответ

0

Это заставляет вас близко:

merged = pd.merge(df1, df2, on='name', suffixes=('', '_r')) 

keep = (merged.top_depth >= merged.top_depth_r) & (merged.bottom_depth <= merged.bottom_depth_r) 

print merged.loc[keep, ['name', 'top_depth', 'bottom_depth', 'attr1', 'attr2']] 

Урожайность:

name top_depth bottom_depth attr1 attr2 
2  a  27   29 10 gamma 
5  a  29   30 2.5 gamma 
8  a  30   32.5 56 gamma 
11 a  32.5   36 18 gamma 
14 a  36   39  5 gamma 
15 b   0   3 0.5 alpha 
19 b   3   6 1.5 alpha 
24 b   6   9 2.5 beta 

Я не знаю, как вы хотите строку:

name top_depth bottom_depth attr1 attr2 
0  a   0   25 NaN alpha 
1  a  25   27 NaN beta 

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

+0

спасибо, что близко. На самом деле, я немного изменил свой первоначальный вопрос, чтобы больше отразить мою потребность. Мне нужно разбить первую строку «df1» (27 -> 28 и 28 -> 29), так как диапазон глубин «df2» не равен диапазону глубины «df1». Я думаю, что это более сложно сделать ... – lorenzo

0

Это нехороший подход, но в этой работе DataFrame. Но это не общее решение.
Проблема заключается в первом и последнем строках со значениями NaN в колонке attr1. И это зависит от данных. Если данные разные, вы не можете использовать это решение.

Мое решение использует особенность объединенном ЦФ, что строки с NaN являются от первой строки до первого значения NaN в столбце attr1 и от последнего NaN значения в колонке attr1 до конца dataframe.

df1 
# name top_depth bottom_depth attr1 
#0 a  27   29 10 
#1 a  29   30 2.5 
#2 a  30   32.5 56 
#3 a  32.5   36 18 
#4 a  36   39  5 
#5 b   0   3 0.5 
#6 b   3   6 1.5 
#7 b   6   9 2.5 

#df2 
# name top_depth bottom_depth attr2 
#0 a   0   25 alpha 
#1 a  25   27 beta 
#2 a  27   39 gamma 
#3 b   0   6 alpha 
#4 b   6   9 beta 
#5 b   9   18 phi 
#6 b  18   25 teta 
#merge data by column name 
df = df1.merge(df2, on='name') 

valid = (df.bottom_depth_x <= df.bottom_depth_y) & \ 
     (df.top_depth_x >= df.top_depth_y) 
df['attr1'] = df[valid].attr1 
print df 
# name top_depth_x bottom_depth_x attr1 top_depth_y bottom_depth_y attr2 
#0  a   27    29 NaN   0    25 alpha 
#1  a   27    29 NaN   25    27 beta 
#2  a   27    29 10   27    39 gamma 
#3  a   29    30 NaN   0    25 alpha 
#4  a   29    30 NaN   25    27 beta 
#5  a   29    30 2.5   27    39 gamma 
#6  a   30   32.5 NaN   0    25 alpha 
#7  a   30   32.5 NaN   25    27 beta 
#8  a   30   32.5 56   27    39 gamma 
#9  a  32.5    36 NaN   0    25 alpha 
#10 a  32.5    36 NaN   25    27 beta 
#11 a  32.5    36 18   27    39 gamma 
#12 a   36    39 NaN   0    25 alpha 
#13 a   36    39 NaN   25    27 beta 
#14 a   36    39  5   27    39 gamma 
#15 b   0    3 0.5   0    6 alpha 
#16 b   0    3 NaN   6    9 beta 
#17 b   0    3 NaN   9    18 phi 
#18 b   0    3 NaN   18    25 teta 
#19 b   3    6 1.5   0    6 alpha 
#20 b   3    6 NaN   6    9 beta 
#21 b   3    6 NaN   9    18 phi 
#22 b   3    6 NaN   18    25 teta 
#23 b   6    9 NaN   0    6 alpha 
#24 b   6    9 2.5   6    9 beta 
#25 b   6    9 NaN   9    18 phi 
#26 b   6    9 NaN   18    25 teta 

#find first and last indexes with non NaN values 
first = df.apply(lambda series: series.first_valid_index()).max() #first = 2 
last = df.apply(lambda series: series.last_valid_index()).min() #last = 24 

#drop all rows with NaN values 
df1 = df.dropna() 
#merging dataframe 
df = pd.concat([df.ix[:first-1], df1, df.ix[last-1:]]).reset_index() 
df = df.rename(columns={'top_depth_x':'top_depth', 'bottom_depth_x':'bottom_depth'}) 
#copy columns for output columns 
df.loc[df['attr1'].isnull() , 'bottom_depth'] = df['bottom_depth_y'] 
df.loc[df['attr1'].isnull() , 'top_depth'] = df['top_depth_y'] 
#drop unnecessary columns 
df = df.drop(['bottom_depth_y','top_depth_y', 'index'], axis=1) 
print df 
# name top_depth bottom_depth attr1 attr2 
#0  a   0   25 NaN alpha 
#1  a  25   27 NaN beta 
#2  a  27   29 10 gamma 
#3  a  29   30 2.5 gamma 
#4  a  30   32.5 56 gamma 
#5  a  32.5   36 18 gamma 
#6  a  36   39  5 gamma 
#7  b   0   3 0.5 alpha 
#8  b   3   6 1.5 alpha 
#9  b   6   9 2.5 beta 
#10 b   0   6 NaN alpha 
#11 b   6   9 2.5 beta 
#12 b   9   18 NaN phi 
#13 b  18   25 NaN teta 
Смежные вопросы