我有一些带有数字,空值和字符的嘈杂数据。我需要检查数字的百分比变化。
为此,我使用正则表达式来检查列中存在的%
符号。 If
是,然后是extract
个数字并减去百分比变化Else
extract
数字并执行计算以获得更改。
以下是可重现的代码
df = data.frame(Actual = c('0.10%','55.10%',NA,'20.8B'),
Previous = c('-0.50%','47.90%',NA,'16.6B'))
df
Actual Previous
1 0.10% -0.50%
2 55.10% 47.90%
3 <NA <NA>
4 20.8B 16.6B
# if loop to calculate percentage change
if(grepl("%", df$Actual) & grepl("%", df$Previous)) {
a = as.numeric(stringr::str_extract(df$Actual,"[-\\d.][\\d]"))
p = as.numeric(stringr::str_extract(df$Previous,"[-\\d.][\\d]"))
df$Gain = a - p
} else {
a = as.numeric(stringr::str_extract(df$Actual,"[-\\d.][\\d]"))
p = as.numeric(stringr::str_extract(df$Previous,"[-\\d.][\\d]"))
df$Gain = (a - p)/p * 100
}
df
Actual Previous Gain
1 0.10% -0.50% 0.6
2 55.10% 47.90% 7.2
3 <NA> <NA> <NA>
4 20.8B 16.6B 4.2
最后一个值应计算为25.30,而不是4.2 if循环的值是:
grepl("%", df$Actual) & grepl("%", df$Previous)
[1] TRUE TRUE FALSE FALSE
最后一行应该是在else循环中。你能帮忙搞错吗?
答案 0 :(得分:2)
您可以使用parse_number
包中的readr
- 函数(其中一个tidyverse
- 包)和ifelse
条件来实现您想要的效果
使用:
library(readr)
library(dplyr)
df %>%
mutate(gain = (parse_number(Actual) - parse_number(Previous)) /
if_else(grepl('%', Actual), 1, parse_number(Previous)/100) )
给出:
Actual Previous gain 1 0.10% -0.50% 0.6000 2 55.10% 47.90% 7.2000 3 <NA> <NA> NA 4 20.8B 16.6B 25.3012
答案 1 :(得分:1)
非dplyr方法可能
df = data.frame(Actual = c('0.10%','55.10%',NA,'20.8B'),
Previous = c('-0.50%','47.90%',NA,'16.6B'), stringsAsFactors = FALSE)
df
percChange <- function(x) {
if (all(grepl("%", x))){
d <- diff(rev(as.numeric(gsub("[^-\\d{1,2}.\\d+]", "", x, perl = TRUE))))
}
else {
n <- rev(as.numeric(gsub("[^-\\d{1,2}.\\d+]", "", x, perl = TRUE)))
d <- diff(n) / n[1] * 100
}
return (d)
}
df$diff <- apply(df, 1, percChange)
df
Actual Previous diff
1 0.10% -0.50% 0.6000
2 55.10% 47.90% 7.2000
3 <NA> <NA> NA
4 20.8B 16.6B 25.3012
另外,关于你的循环有什么问题 - 运行它会引发以下错误:
Warning message:
In if (grepl("%", df$Actual) & grepl("%", df$Previous)) { :
the condition has length > 1 and only the first element will be used
意味着只使用第一个元素(TRUE
,因为第一行具有两列的%值)。所以你在第4行的结果是20-16 = 4
!您必须遍历行以防止此