R语言数据框处理:拆分State列保留州名、提取年份至新列
问题描述
数据框的State列混合存储了三类信息:州名、HB/HF法案编号、法律生效日期。需要实现两个需求:
- 处理后
State列仅保留州名 - 新增一列存储对应法律的生效年份
现有预处理代码如下:
Mintz = read.csv('https://github.com/bandcar/mintz/raw/main/State%20Legislation%20on%20Biosimilars2.csv') mintz = Mintz # 删除第二列为空值的行 mintz = mintz[mintz$Substitution.Requirements != "", ] # 删除第一列值为"State"的冗余表头行 mintz=mintz[mintz$State != "State", ] # 重置行号 mintz= mintz %>% data.frame(row.names = 1:nrow(.)) # 删除第34行的波多黎各(PR,非美国州级单位) mintz = mintz[-34,] # 重置行号 mintz= mintz %>% data.frame(row.names = 1:nrow(.))
最初判断可以用strsplit()搭配gsub()实现需求,但因为State列内容没有固定分隔符,不清楚具体编写逻辑。
问题补充
目前仍未实现State列仅保留州名的需求。
关于年份提取,找到了一段可运行代码,但不理解其生效逻辑,且存在异常:
mintz2 = mintz mintz2$Year = sub('.*(\\d{4}).*', '\\1', mintz2$State)
疑问点:
- 之前认知里
\d是匹配字面字符,.匹配单个字符,无法理解\1的含义 - 第20行明尼苏达州的数据没有对应年份时,代码提取到了非数字字符,和
\d仅匹配数字的认知冲突
解答
正则代码原理解释
你对正则语法的认知存在几个偏差,先逐点说明:
- 正则中
\d不是匹配字面字符"d",而是匹配0-9的任意单个数字,在R的字符串语法中需要写双反斜杠\\d才能表示正则转义的\d - 正则中
.匹配任意单个字符,.*表示匹配任意长度(包含0长度)的任意字符 - 小括号
()在正则中表示捕获组,会把括号内匹配到的内容临时存储,替换字符串里的\\1就是引用第一个捕获组存储的匹配内容
你找到的这行代码逻辑是:匹配「任意前缀 + 连续4位数字 + 任意后缀」的整段字符串,把整段内容替换为捕获组抓到的4位连续数字,也就是年份。
明尼苏达行出现非数字结果的原因很简单:如果字符串里找不到符合规则的匹配项,sub()不会执行替换,会直接返回原始字符串,自然就会出现非数字的结果。
修复年份提取逻辑
要解决无匹配时返回原字符串的问题,加一层匹配判断即可,找不到4位连续数字时返回NA:
# 方法1:用stringr包的str_extract,无匹配默认返回NA,代码更简洁 library(stringr) mintz$Year = as.integer(str_extract(mintz$State, "\\d{4}")) # 方法2:基础R实现,不需要额外装包 mintz$Year = ifelse( grepl("\\d{4}", mintz$State), as.integer(sub('.*(\\d{4}).*', '\\1', mintz$State)), NA_integer_ )
提取纯净州名
观察State列的内容规律:所有州名都是纯英文字母(包含空格),后续的法案编号、生效日期都是从第一个数字,或者HB/HF/SB这类法案前缀开头的。只要把第一个数字/法案前缀及其之后的所有内容清空,再去掉首尾多余空格即可:
# 匹配第一个出现的数字、HB/HF/SB标识,将该位置及之后的所有内容替换为空 mintz$State = trimws(sub("(\\d|HB|HF|SB).*", "", mintz$State))
运行后逐行检查即可确认,所有州名都被正确提取,没有残留法案编号或日期内容。
内容的提问来源于stack exchange,提问作者bandcar
相关产品推荐
相关产品推荐

