如果循环计算到所有记录

问题描述 投票:1回答:2

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

r
2个回答
2
投票

您可以使用parse_number-package(readr-packages中的一个)的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
投票

非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!你必须遍历行以防止这种情况

© www.soinside.com 2019 - 2024. All rights reserved.