grepl 不能用在 Apply 函数中吗?

Can't grepl be used in Apply function?

我有一个数据框,其值如下:

BrandName  Expense
Apple      .8B
Google     .2B
GE         -
facebook   1M
McDonald   9M

我想清理这些费用值,使它们最终达到相同的规模(以十亿为单位)。对于 ex,最终数据框应如下所示:

BrandName  Expense
Apple      1.8
Google     3.2
facebook   0.281
McDonald   0.719

$ 可以通过 gsub 简单地删除。这可以。但是之后我遇到了问题。 我正在应用一个函数 A,它使用 grepl 检查值是否包含 'M',如果为真(去掉 'M',转换为数值,然后除以 1000) 如果它 returns false (strip 'B', convert to numeric value)

A <- function(x){
  if (grepl("M", x))
  {
    str_replace(x, "M", "")
    as.numeric(x)
    x <- x/1000
  }
  else if (grepl("B", x))
  {
    str_replace(x, "B", "")
    as.numeric(x)
  }
}
frame <- data.frame(frame[1], apply(frame[2],2, A))

但所有费用值在最终结果中都是 NA。 在进一步分析中,我注意到所有值都在 elseif 部分。 我在 apply 函数中使用了 grepl 吗?如果是,我该如何解决。

或解决此特定问题的任何其他更好的解决方案?

我们可以用 gsubfn 做到这一点。我们用 sub 删除 $,然后使用 gsubfn 将 'B' 和 'M' 替换为 1* 1/1000,循环通过 vector 并评估字符串。

library(gsubfn)
df1$Expense <-  unname(sapply(gsubfn("([A-Z])$", list(B=1, M=' * 1/1000'), 
          sub("[$]", "", df1$Expense)), function(x) eval(parse(text=x))))
df1
#   BrandName Expense
#1     Apple   1.810
#2    Google   3.210
#3  facebook   0.281
#4  McDonald   0.719

或者 base R 选项将提取数字子字符串 ('val'),末尾的子字符串 ('nm1'),将 'val' 转换为数字并根据子字符串 'nm1' 与创建的 key/value' 字符串的匹配乘以 1, 1/1000。

val <- gsub("[^0-9.]+", "", df1$Expense)
nm1 <- sub(".*(.)$", "\1", df1$Expense)
df1$Expense <-  as.numeric(val)*setNames(c(1, 1/1000), c("B", "M"))[nm1]
df1
#  BrandName Expense
#1     Apple   1.800
#2    Google   3.200
#3  facebook   0.281
#4  McDonald   0.719

注意:这也应该扩展,以防两种方法中有万亿、数千等,即在 list(...) 内的第一个方法更改,第二个我们通过创建更多 [= setNames(c(1, ...), c("B", "M", ...))

中的 45=] 个组

另一个选项是 parse_number 来自 readrdplyr

library(dplyr)
library(readr)
df1 %>% 
   mutate(Expense = parse_number(Expense)/c(1, 1000)[grepl("M", Expense)+1])
#   BrandName Expense
#1     Apple   1.800
#2    Google   3.200
#3  facebook   0.281
#4  McDonald   0.719

数据

df1 <- structure(list(BrandName = c("Apple", "Google", "facebook", "McDonald"
), Expense = c(".8B", ".2B", "1M", "9M")), .Names = c("BrandName", 
"Expense"), class = "data.frame", row.names = c(NA, -4L))

这是一个基本的 R 解决方案,根据您的需要,它可能更适合您的问题:

df$ExpenseScaled <- as.numeric(gsub("[$MB]", "", df$Expense))
m.index          <- substr(df$Expense, nchar(df$Expense), nchar(df$Expense)) == 'M'
df$ExpenseScaled[m.index] <- df$ExpenseScaled[m.index] / 1000

 df
 BrandName Expense ExpenseScaled
1     Apple   .8B         1.800
2    Google   .2B         3.200
3  Facebook   1M         0.281
4 McDonalds   9M         0.719

第一行代码删除美元符号和金额符号(BM)以获得数字金额。接下来的两行代码根据您的规范有条件地将数百万数字除以 1000。