使用forloop根据r中的条件修复值

时间:2016-12-19 07:44:33

标签: r function for-loop dataframe while-loop

我正在尝试修复数据中的异常值,并将数据转换为R中下面组织的结构。

company_1(数据框中的一列)有12行数据,每6行数据指的是一个句点,因此有2个句点。

    company_1
1     123
2     0
3     567
4     0
5     987
6     678
7     657
8     567
9     543
10    345
11    2341
12    5432

我正在寻找的是:对于我的数据框中的每一列,我想将0和大于其标准差的值修复为相应的时间段值(+或 - 6行) ),如果相应的时间段值也是异常值,则它会查找下一个(或前一个)对应的时间段值,直到检查完所有相应的时间段值。

我在下面尝试过代码,想法是将一个列数据填充到矩阵中,然后第一行将是原始列的第6行和第12行,第18行的值。

> sd.value <- as.numeric(apply(df,2, function(x) sd(x, na.rm = TRUE)))
> for(i in 1:dim(df)[2]){
>        for(j in 1:dim(df)[1]){
>          if(df[j,i] == 0 | df[j,i] >= sd.value[i]*3){
>            df[j,i] <- matrix(data = df[,i], nrow = 6, ncol = 2)[j,][matrix(data = df[,i], nrow = 6, ncol = 2)[j,]!=0 & matrix(data
> = df[,i], nrow = 6, ncol = 2)[j,] <= sd.value[i]*3][1] 
>          } else{
>            df[j,i] <- df[j,i]
>          }
>        }
>      }

矩阵将是这样的:

  [,1]   [,2]
[1,] 123  657
[2,] 0    567
[3,] 567  543
[4,] 0    345
[5,] 987 2341
[6,] 678 5423

但是,这个for循环只能处理前6个值。这是因为,例如,对于原始列中的第8行,它应该检查该矩阵中的第2行值并确定是否需要修复它。但是,我不知道如何指示R检查&#39;矩阵的第二行,而i = 8,14 ......

感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

以下功能可能对您有所帮助。 fixCol用于根据条件固定向量中的值:0和大于其标准差的值被定义为异常值。异常值将被下一个非异常值对应的时间段值(+6行)替换。如果不存在这种非异常值,则异常值保持不变。

fixCol接受data.frame的向量或列作为输入,并返回固定向量。

注意:代码使用dplyr包和链接%&gt;%来修改data.frame。这比循环更有效,并且易于理解。

希望它有所帮助!

library(dplyr)
# fill NA values using the new non-NA value
# the NAs after the last non-NA values are unchanged
fillNaUseNextNonNa <- function(vecTest)
{
    vecPre <- rep(vecTest[!is.na(vecTest)], diff(c(0,which(!is.na(vecTest)))))
    vecNew <- c(vecPre, rep(NA, length(vecTest)-length(vecPre)))
    return(vecNew)
}

# use the closet precedent non-na value to replace. if not found, use the closet following non-na value
fillNaBackward <- function(vecTest)
{
    if(all(is.na(vecTest))) stop("All values are NA or invalid")
    # (firstNonNaValue, vecTest)
    vecTest <- c(vecTest[which(!is.na(vecTest))[1]], vecTest)
    vecAfterTest <- rep(vecTest[!is.na(vecTest)], diff(c(which(!is.na(vecTest)), length(vecTest)+1)))
    # vecNew <- c(vecPre, rep(NA, length(vecTest)-length(vecPre)))
    return(vecAfterTest[-1])
} 

# fix the values in a vector based on conditions in R
fixCol <- function(vecNum){
    sdValueTri <- sd(vecNum, na.rm = TRUE)
    # vecValid <- (vecNum == 0 | vecNum >= sdValueTri)
    dfTmp <-data.frame(num = vecNum, valid = !(vecNum == 0 | vecNum >= sdValueTri))
    # group

    # then fix
    dfTmp <- dfTmp %>% 
        group_by(group=row_number()%%6) %>%
        mutate(numNew = ifelse(valid, num, NA)) %>%
        mutate(numNew = fillNaBackward(numNew)) %>%
        mutate(numNew = ifelse(is.na(numNew), num, numNew)) %>%
        ungroup() %>%
        select(numNew)
    return(dfTmp$numNew)
}

# example
df <- data.frame(company_1 = c(123,0,567,0,987,678,657,567,543,345,2341,5432))
df <- df %>% mutate(company_1_fix = fixCol(company_1))
# df$company_1_fix
# 123 567 567 345 987 678 657 567 543 345 987 678