pandas 包含间隔的列中的查找值
pandas lookup value in column containing Intervals
我正在尝试根据连续值落入的范围将一列连续浮点值映射到一些离散(分桶)值
例如
df_lookup = pd.DataFrame(data=[[0.0, 0.3, 10.1],
[0.3, 0.65, 30.3],
[0.65, 1.0, 50.5]],
columns=['start', 'end', 'mapped_value'])
# create intervals
df_lookup['interval'] = df_lookup.apply(lambda x:
pd.Interval(x['start'],
x['end'],
closed='both' if x['end']==1.0 else 'left'), axis=1)
df_lookup
输出:
start
end
mapped_value
interval
0
0.00
0.30
10.1
[0.0, 0.3)
1
0.30
0.65
30.3
[0.3, 0.65)
2
0.65
1.00
50.5
[0.65, 1.0]
df_data=pd.DataFrame(data=[['A', 0.3],
['B', 0.65],
['C', 0.6],
['D', 0.75],
['E', 0.4]],
columns=['ID', 'original_value'])
df_data
ID
original_value
0
A
0.30
1
B
0.65
2
C
0.60
3
D
0.75
4
E
0.40
此时我使用 pandas.DataFrame.apply
来获取我的查找值,但是
df_data['mapped_value'] = df_data.apply(
lambda x: df_lookup.loc[x['original_value'] in df_lookup['interval']]['mapped_value'],
axis=1)
但这爆炸告诉我 KeyError: 'False: boolean label can not be used without a boolean index'
进一步调查表明,我遇到的问题是,当我执行 in
时,我只得到一个布尔值 return 而不是布尔值列表,例如,数据 ID= 'A'
其中 original value
是 0.3,我希望 x['original_value'] in df_lookup['interval']
会 return [False, True, False]
但实际上它 returning False
我希望能就如何实现此“查找”映射提供一些指导。谢谢
如果间隔可能不相交,您可以使用 pandas.merge_asof
对上限进行可选检查:
df_data['mapped_value'] = (pd
.merge_asof(df_data.sort_values(by='original_value'),
df_lookup,
left_on='original_value', right_on='start')
# assign command below is only required if the intervals are disjoint
.assign(mapped_value=lambda d: d['mapped_value']
.mask(d['end'].lt(d['original_value'])))
['mapped_value']
)
输出:
ID original_value mapped_value
0 A 0.30 30.3
1 B 0.65 30.3
2 C 0.60 30.3
3 D 0.75 50.5
4 E 0.40 50.5
Series.map
的解决方案
无需创建中间 interval
列,您应该创建一个 IntervalIndex
可用于替换 df_data
中的值
i = pd.IntervalIndex.from_arrays(df_lookup.start, df_lookup.end, closed='left')
df_data['mapped_value'] = df_data['original_value'].map(df_lookup.set_index(i)['mapped_value'])
结果
print(df_data)
ID original_value mapped_value
0 A 0.30 30.3
1 B 0.65 50.5
2 C 0.60 30.3
3 D 0.75 50.5
4 E 0.40 30.3
我正在尝试根据连续值落入的范围将一列连续浮点值映射到一些离散(分桶)值
例如
df_lookup = pd.DataFrame(data=[[0.0, 0.3, 10.1],
[0.3, 0.65, 30.3],
[0.65, 1.0, 50.5]],
columns=['start', 'end', 'mapped_value'])
# create intervals
df_lookup['interval'] = df_lookup.apply(lambda x:
pd.Interval(x['start'],
x['end'],
closed='both' if x['end']==1.0 else 'left'), axis=1)
df_lookup
输出:
start | end | mapped_value | interval | |
---|---|---|---|---|
0 | 0.00 | 0.30 | 10.1 | [0.0, 0.3) |
1 | 0.30 | 0.65 | 30.3 | [0.3, 0.65) |
2 | 0.65 | 1.00 | 50.5 | [0.65, 1.0] |
df_data=pd.DataFrame(data=[['A', 0.3],
['B', 0.65],
['C', 0.6],
['D', 0.75],
['E', 0.4]],
columns=['ID', 'original_value'])
df_data
ID | original_value | |
---|---|---|
0 | A | 0.30 |
1 | B | 0.65 |
2 | C | 0.60 |
3 | D | 0.75 |
4 | E | 0.40 |
此时我使用 pandas.DataFrame.apply
来获取我的查找值,但是
df_data['mapped_value'] = df_data.apply(
lambda x: df_lookup.loc[x['original_value'] in df_lookup['interval']]['mapped_value'],
axis=1)
但这爆炸告诉我 KeyError: 'False: boolean label can not be used without a boolean index'
进一步调查表明,我遇到的问题是,当我执行 in
时,我只得到一个布尔值 return 而不是布尔值列表,例如,数据 ID= 'A'
其中 original value
是 0.3,我希望 x['original_value'] in df_lookup['interval']
会 return [False, True, False]
但实际上它 returning False
我希望能就如何实现此“查找”映射提供一些指导。谢谢
如果间隔可能不相交,您可以使用 pandas.merge_asof
对上限进行可选检查:
df_data['mapped_value'] = (pd
.merge_asof(df_data.sort_values(by='original_value'),
df_lookup,
left_on='original_value', right_on='start')
# assign command below is only required if the intervals are disjoint
.assign(mapped_value=lambda d: d['mapped_value']
.mask(d['end'].lt(d['original_value'])))
['mapped_value']
)
输出:
ID original_value mapped_value
0 A 0.30 30.3
1 B 0.65 30.3
2 C 0.60 30.3
3 D 0.75 50.5
4 E 0.40 50.5
Series.map
的解决方案
无需创建中间 interval
列,您应该创建一个 IntervalIndex
可用于替换 df_data
i = pd.IntervalIndex.from_arrays(df_lookup.start, df_lookup.end, closed='left')
df_data['mapped_value'] = df_data['original_value'].map(df_lookup.set_index(i)['mapped_value'])
结果
print(df_data)
ID original_value mapped_value
0 A 0.30 30.3
1 B 0.65 50.5
2 C 0.60 30.3
3 D 0.75 50.5
4 E 0.40 30.3