如何用dplyr mutate转换data.table列值为0/1?最优实现方式
嘿,这个问题我刚好碰到过类似的情况,来给你捋捋怎么用dplyr最地道地解决!
首先得明确核心问题:你说这些列被识别为Integer类型,但实际存的是带0/1或./.开头的字符串——这其实是R读取数据时的类型识别误差,因为这种含特殊字符的字符串根本没法存成Integer,大概率是读取时被强制转成Integer后变成了NA,或者你的列本质是Character类型但显示上被标记成了Integer?不管怎样,第一步必须把这些列转换成字符型,不然根本没法做字符串开头的判断。
接下来用dplyr的mutate+across批量处理除首列外的所有列,这比一个个列名写高效多了。这里有两种常用写法,看你习惯:
方法1:用stringr的str_starts(更直观的正则匹配)
先加载必要的包:
library(dplyr) library(stringr)
然后处理数据:
processed_data <- your_data_table %>% # 把第一列之外的所有列转成字符型 mutate(across(-1, as.character)) %>% # 批量判断开头并替换 mutate(across(-1, ~case_when( str_starts(., "^0/1") ~ 1L, # 匹配以0/1开头的,换成整数1 str_starts(., "^\\./\\.") ~ 0L, # 匹配以./.开头的,换成整数0(注意转义.,因为正则里.是任意字符) TRUE ~ NA_integer_ # 其他情况设为NA,你可以根据需求改成别的值 )))
方法2:用base R的substr(不用额外加载stringr)
如果不想装stringr包,直接取前3个字符判断:
processed_data <- your_data_table %>% mutate(across(-1, as.character)) %>% mutate(across(-1, ~if_else( substr(., 1, 3) == "0/1", 1L, if_else(substr(., 1, 3) == "./.", 0L, NA_integer_) )))
为什么之前用recode没成功?
因为recode是精确值匹配,它要求整个值完全等于你指定的键,但你的需求是匹配字符串的开头,不是整个字符串完全一致——比如你的值是0/1:3:0,...,整个字符串和0/1不一样,所以recode找不到匹配项自然没用。再加上之前列是Integer类型,里面的字符串早被转成NA了,recode也没法处理这些NA对应的原始内容。
另外,如果你习惯用data.table的原生语法,其实也可以结合dplyr的逻辑,但上面的写法已经是dplyr里最地道的批量处理方式了,不管你的输入是data.table还是tibble都适用。
内容的提问来源于stack exchange,提问作者Alessandro
相关产品推荐
相关产品推荐

