使用R,我得到的数据看起来像:
A, B
= =====
x," 120"
y," 2300"
z,"1.2 M"
x," 4500"
x," 42 M"
这是使用构建的
A <- c("x","y","z","x","x")
B <- c(" 120", " 2300", "1.2 M", " 4500", " 42 M")
data <- data.frame(A, B)
我想将第二列转换为一个有效的数字("M"表示数百万(。我拥有的是:
df <- data %>%
mutate( B = ifelse( grepl("^ *[0-9]+$", .$B),
as.numeric(.$B),
1000000 * as.numeric(sub(" *([0-9]+) M", "\1", .$B))))
即。它寻找一个带有"M"的字段,如果找到,则在sustricg上做as.numeric并乘以1000000。
这很好,除非我收到警告:
Warning messages:
1: Problem with `mutate()` input `B`.
i NAs introduced by coercion
i Input `B` is `ifelse(...)`.
2: In ifelse(grepl("^ *[0-9]+$", .$B), as.numeric(.$B), 1e+06 * :
NAs introduced by coercion
但当我使用df %>% filter(is.na(B))
检查数据时,没有NAs
我不想完全禁用警告,但我确实想在";无效";。
有什么建议吗?阿美,我错过什么了?
得到警告的原因是因为ifelse
/if_else
/case_when
在yes
和no
部分都传递了整个向量。稍后将根据条件决定要返回的输出。
因此,我们认为我们只将as.numeric(B)
应用于那些满足条件的数字,但实际上,它与应用as.numeric(data$B)
相同,后者给出了相同的警告,即B
中很少有值不能转换为数字。因此,您需要以一种根本不会为任何值生成警告的方式使用ifelse
(@r2evans已经显示了这一点(,或者在没有ifelse
的情况下单独应用操作。
data$C <- NA_real_
inds <- grepl("^ *[0-9]+$", data$B)
data$C[inds] <- as.numeric(B[inds])
data$C[!inds] <- 1000000 * as.numeric(sub(" *([0-9]+) M", "\1", data$B[!inds]))
我有一个未完全测试的函数,它是我编写的另一个函数的伴侣(它松散地基于utils:::format.object_size
(。
unKMG <- function(s, standard = "SI") {
known_bases <- c(legacy = 1024, IEC = 1024, SI = 1000)
known_units <- list(SI = c("", "k", "M", "G", "T", "P",
"E", "Z", "Y"), IEC = c("", "Ki", "Mi", "Gi",
"Ti", "Pi", "Ei", "Zi", "Yi"), legacy = c("", "K",
"M", "G", "T", "P"))
standard <- match.arg(standard, c("auto", names(known_bases)))
powers <- known_bases[[standard]] ^
(setNames(seq_along(known_units[[standard]]), known_units[[standard]])-1)
sapply(strsplit(trimws(s), "[[:space:]]+"),
function(z) {
nums <- suppressWarnings(as.numeric(z))
prod(nums[!is.na(nums)], powers[names(powers) %in% z[is.na(nums)]])
})
}
unKMG(dat$B)
# [1] 120 2300 1200000 4500 42000000
但如果你想要一次机会,试试
as.numeric(gsub(".*\b(-?[0-9]+\.?[0-9]*)\b.*", "\1", dat$B)) *
ifelse(grepl("M", dat$B), 1000000, 1)
# [1] 120 2300 12000000 4500 42000000
dat %>%
mutate(
B = as.numeric(gsub(".*\b(-?[0-9]+\.?[0-9]*)\b.*", "\1", B)) *
ifelse(grepl("M", B), 1000000, 1)
)
正则表达式的解释:
.*
任何东西(不包括任何东西(\b
一个字边界,不消耗(包含(;例如,这确保了我们不会在较大的数字中间开始或结束一个数字(...)
组,在第二个自变量中被引用为\1
- 负符号的
-?
0或1 [0-9]+
1位或1位以上- 小数点的
\.?
0或1(对于不同的语言环境,替换为,
或[,.]
( [0-9]*
0位或更多数字
(如果你没有注意到的话,我把我的数据命名为dat
……当我把data
放错地方时,我已经被invalid 'type' (closure) of argument
的错误咬了太多次了,现在我倾向于使用其他与基本R函数不冲突的名称。(