如果循环计算到所有记录

时间:2017-12-20 12:53:55

标签: r

我有一些带有数字,空值和字符的嘈杂数据。我需要检查数字的百分比变化。 为此,我使用正则表达式来检查列中存在的%符号。 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循环中。你能帮忙搞错吗?

2 个答案:

答案 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!您必须遍历行以防止此