R语言如何修改或删除不符合列正则模式的行,提取时间列小时值
混杂时间字段的小时值提取方法
实际场景
当前处理鲨鱼攻击事件数据集,需要从格式杂乱的时间字段提取小时值,用于24小时分箱的事件发生次数统计。
测试样例与预期输出:
Times <- c("12h00","16h30","Afternoon","15h00","14h20","7h30","06h00") # 期望输出:["12","16",NA,"15","14","7","6"]
字段值的分布规则:
- 绝大多数条目为
##h##格式(如07h30) - 少量条目为
#h##的单数字小时格式(如7h30) - 夹杂非标准时间文本(如
Afternoon),这类值需要统一置为NA
最初的实现思路是用str_replace_all(Time, pattern, replacement)完成提取,初步想到的正则模式为"^\\d{2}h\\d{2}$",但存在两个未解决的问题:
- 不满足正则匹配规则的条目无法自动置为NA
- 无法覆盖单数字小时的时间格式
具体实现方案
适配stringr包的轻量实现
不需要硬靠str_replace_all做全量替换,直接用str_extract()匹配目标内容,未匹配到目标的位置会自动返回NA,天然解决非标准值转NA的问题:
library(stringr) # 匹配规则:从字符串开头抓取1-2个连续数字,且该数字后面紧跟字母h hour_vals <- str_extract(Times, "^\\d{1,2}(?=h)")
运行后输出结果:
[1] "12" "16" NA "15" "14" "7" "06"
如果需要把带前导0的06转换为对齐要求的6,只要把结果转成整数类型即可,整数转换会自动去掉前导0:
hour_vals <- as.integer(str_extract(Times, "^\\d{1,2}(?=h)")) # 转换后结果:12 16 NA 15 14 7 6
说明:正则里的
(?=h)是正向先行断言,只匹配h前面的数字,不会把h后面的分钟数误提取出来;设置\\d{1,2}的匹配长度,可以同时覆盖2位小时(如12h00)和1位小时(如7h30)的场景,不需要写多分支判断。
你之前设想的^\\d{2}h\\d{2}$存在两个适配问题:一是要求字符串必须是固定长度的两位数字+h+两位数字格式,匹配不到单数字小时的条目;二是如果用该模式做字符串替换,不匹配的条目会保留原始文本,不会自动转为NA,调整后的匹配逻辑可以同时解决这两个问题。
基础R原生实现(无需加载第三方包)
如果不想依赖外部包,用base R的字符串函数也能实现同等效果:
# 匹配「开头数字+h」的格式,把捕获到的第一组数字保留作为小时值 hour_vals <- sub("^(\\d{1,2})h.*$", "\\1", Times) # 筛选出没被成功替换的非标准值,统一置为NA hour_vals[!grepl("^\\d{1,2}h", Times)] <- NA # 转成整数自动移除前导0 hour_vals <- as.integer(hour_vals)
运行结果和stringr方案完全一致。
后续直方图制作参考
提取完成的小时值可以直接传给绘图函数做分箱统计,不需要额外做区间预处理:
# 以0-24为区间边界做直方图 hist(hour_vals, breaks = 0:24, main = "鲨鱼攻击事件小时分布", xlab = "事件发生小时")
内容的提问来源于stack exchange,提问作者norsynthz
相关产品推荐
相关产品推荐

