看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
在以下数据中,筛选出n列的数字在对应Interval列的区间里的数据,其中Interval的区间表达是一个字符串,后边三个值没有区间定义。
# 筛选出n列的数字在对应Interval列的区间里的数据
'''
n Interval
12 (1,11)
4 (2,5)
6 (6,11)
12 (1,10)
14 (9,18)
36 (12,12)
12 (11,20)
13
5
8
'''
用简单的办法是,增加两个辅助列,一个为区间左侧的数字,另外一个为区间右侧的数字,然后判断n是否大于左侧小于右侧。
# 用剪贴板读取数据
df = pd.read_clipboard()
(
df.loc[df.Interval.notna()] # 删除无区间的数据
.assign(left=df.Interval.str.findall(r'\d+').str[0]) # 取左侧
.assign(right=df.Interval.str.findall(r'\d+').str[1]) # 取右侧
.astype({'left': np.int64, 'right': np.int64}) # 将取出的左右数据转为整型
.loc[lambda x: (x.n>x.left) & (x.n<x.right)] # 筛选出结果
)
'''
n Interval left right
1 4 (2,5) 2 5
4 14 (9,18) 9 18
6 12 (11,20) 11 20
'''
我们尝试用第二种方法来解决这个问题,大体思路是用explode炸开类似列表的列,这样会形成一个区间数据,左值在上,右值在下,然后筛选出n大于上值小于下值的行。
(
df.assign(d=df.Interval.str.findall(r'\d+')) # 转为列表
.explode('d') # 炸开列表
)
'''
n Interval d
0 12 (1,11) 1
0 12 (1,11) 11
1 4 (2,5) 2
1 4 (2,5) 5
2 6 (6,11) 6
2 6 (6,11) 11
3 12 (1,10) 1
3 12 (1,10) 10
4 14 (9,18) 9
4 14 (9,18) 18
5 36 (12,12) 12
5 36 (12,12) 12
6 12 (11,20) 11
6 12 (11,20) 20
7 13 NaN NaN
8 5 NaN NaN
9 8 NaN NaN
'''
接着做些数据处理,进行筛选,得到结果:
(
df.assign(d=df.Interval.str.findall(r'\d+')) # 转为列表
.explode('d') # 炸开列表,形成辅助列 d
.replace({pd.NA: 0}) # 将缺失值替换为0
.astype({'d': np.int64}) # 将d转为整型
.loc[lambda x: (x.n > x.d) & (x.n < x.d.shift(-1)) ] # 筛选
)
'''
n Interval d
1 4 (2,5) 2
4 14 (9,18) 9
6 12 (11,20) 11
'''
也可以完成需求,不过本方法逻辑较为复杂,可以帮助我们了解explode和shift的操作原理。
最后,也可以考虑 pandas 提供的 pd.Interval()
区间间隔方法进行判断,可参考教程进行了解 gairuo.com/p/pandas-interval。
更新时间:Aug. 18, 2024, 3:41 p.m. 标签:pandas python 区间