查找由pandas dataframe中的起点和终点定义的共享子范围

时间:2017-07-04 08:56:03

标签: python pandas

我需要组合两个包含有关列车轨道部分信息的数据框:当“线”标识轨道部分时,为起点和终点定义的线的子部分给出两个属性“A”和“B”。点上线;这些小节在两个数据帧之间不匹配:

df1
Line    startpoint  endpoint    Attribute_A 
100     2.506       2.809       B-70
100     2.809       2.924       B-91
100     2.924       4.065       B-84
100     4.065       4.21        B-70
100     4.21        4.224       B-91
...

df2
Line    startpoint  endpoint    Attribute_B 
100     2.5         2.6         140
100     2.6         2.7         158
100     2.7         2.8         131
100     2.8         2.9         124
100     2.9         3.0         178

...

我需要的是一个合并的数据框,它为我们分享它们的相应最小子部分提供了属性A和B的组合:

df3
Line    startpoint  endpoint    Attribute_A Attribute_B
100     2.5         2.506       nan         140
100     2.506       2.6         B-70        140
100     2.6         2.7         B-70        158
100     2.7         2.8         B-70        131
100     2.8         2.809       B-70        124
100     2.809       2.9         B-91        124
100     2.9         2.924       B-91        178
100     2.924       3.0         B-84        178
...

我怎样才能在python中做到最好?我对它有些新意见,当我在行和列之间进行基本计算时,我就是这个问题的结局。合并和排序两个数据帧并计算起点/终点之间各自差异的方法并没有让我走得太远,我似乎无法在论坛上找到适用的信息。我很感激任何提示!

1 个答案:

答案 0 :(得分:0)

这是我的解决方案,有点长但是有效:

第一步是找到间隔:

all_start_points = set(df1['startpoint'].values.tolist() + df2['startpoint'].values.tolist())
all_end_points = set(df1['endpoint'].values.tolist() + df2['endpoint'].values.tolist())

all_points = sorted(list(all_start_points.union(all_end_points)))

intervals = [(start, end) for start, end in zip(all_points[:-1], all_points[1:])]

然后我们需要在每个数据帧中找到相关的区间(如果存在):

import numpy as np
def find_interval(df, interval):
    return df[(df['startpoint']<=interval[0]) &
              (df['endpoint']>=interval[1])]

attr_A = [find_interval(df1, intv)['Attribute_A'] for intv in intervals]
attr_A = [el.iloc[0] if len(el)>0 else np.nan for el in attr_A]

attr_B = [find_interval(df2, intv)['Attribute_B'] for intv in intervals]
attr_B = [el.iloc[0] if len(el)>0 else np.nan for el in attr_B]

最后,我们将所有内容放在一起:

out = pd.DataFrame(intervals, columns = ['startpoint', 'endpoint'])
out = pd.concat([out, pd.Series(attr_A).to_frame('Attribute_A'), pd.Series(attr_B).to_frame('Attribute_B')], axis = 1)
out['Line'] = 100

我得到了预期的结果:

out
Out[111]: 
    startpoint  endpoint Attribute_A  Attribute_B  Line
0        2.500     2.506         NaN        140.0   100
1        2.506     2.600        B-70        140.0   100
2        2.600     2.700        B-70        158.0   100
3        2.700     2.800        B-70        131.0   100
4        2.800     2.809        B-70        124.0   100
5        2.809     2.900        B-91        124.0   100
6        2.900     2.924        B-91        178.0   100
7        2.924     3.000        B-84        178.0   100
8        3.000     4.065        B-84          NaN   100
9        4.065     4.210        B-70          NaN   100
10       4.210     4.224        B-91          NaN   100