2015-09-30 249 views
2

我想在列Id和top_depth和bottom_depth上合并两个数据帧。
我想从左边的df取得每条记录,如果可用的话,如果'深度'落在'top_depth'和'bottom_depth'之间,则从右边的df分配一条记录。根据深度范围合并两个熊猫数据帧

这里是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

非常感谢。其实,我稍微修改了我原来的问题,以反映更多的需求。由于'df2'的深度范围不等于'df1'的深度范围,所以我必须分割'df1'的第一行(27→28和28→29)。我认为这样做比较棘手... – lorenzo

0

这不是很好的方法,但在这个数据框的工作。但这不是一般的解决方案。
问题是第NaNattr1中的第一行和最后一行的值为NaN。这取决于数据。如果数据不同,则不能使用此解决方案。

我的解决方案使用合并DF与NaN行是从第一行到attr1列,并从attr1列数据框结束最后NaN值第一的NaN值的功能。

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