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
来自 readr
和 dplyr
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
第一行代码删除美元符号和金额符号(B
或 M
)以获得数字金额。接下来的两行代码根据您的规范有条件地将数百万数字除以 1000。
我有一个数据框,其值如下:
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", ...))
另一个选项是 parse_number
来自 readr
和 dplyr
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
第一行代码删除美元符号和金额符号(B
或 M
)以获得数字金额。接下来的两行代码根据您的规范有条件地将数百万数字除以 1000。