2016-10-05 97 views
0

我是R新手,我有以下数据(示例)作为csv文件,并且我想要替换任何重复值,如果它们出现在类似年份中的连续日期以及一个月零或一封信。我只需要保持一个平均值。在r中使用多个条件替换重复值

Year Month Day Average 
2013 8  28 2.3 
2013 8  29 2.3 
2013 8  30 1.7 
2013 8  31 1.7 
2014 8  7 3 
2014 8  6 3 
2014 8  8 3 
2014 8  9 3 
2014 9  11 5.8 
2014 9  12 5.8 
2014 9  13 5.8 

我希望得到的结果是这样的

Year Month Day Average 
2013 8  28 2.3 
2013 8  29 0 
2013 8  30 1.7 
2013 8  31 0 
2014 8  7 3 
2014 8  6 0 
2014 8  8 0 
2014 8  9 0 
2014 9  11 5.8 
2014 9  12 0 
2014 9  13 0 

此外,我想能够删除具有被替换像这样的重复值的行:

Year Month Day Average 
2013 8  28 2.3 
2013 8  30 1.7 
2014 8  7 3 
2014 9  11 5.8 

我必须有两个文件,其中一个的重复值由零或一个字母替换,而另一个文件只有没有重复值的平均值。

预先感谢您!

+0

请考虑使用'dput'或类似的东西来分享您的数据,这样可以更容易地帮助您。 – NGaffney

+1

连续两天,如果数据不同,那么它是有意义的,但如果它轮到相同的数字,那么你放弃它?我不知道底层数据,但听起来你会扔掉潜在的好数据。另外,订单是否重要?除了2014/8/6之外,所有数据都保持较早的平均水平。 – r2evans

回答

0

使用dplyr进行data.frame操作,使用日期偏移 操作和diff来查找连续的重复值。

请注意,我还对日期进行了排序以保留最早的日期,这使得它与示例解决方案不完全匹配。

library(dplyr) 

## 
## Attaching package: 'dplyr' 

## The following objects are masked from 'package:stats': 
## 
##  filter, lag 

## The following objects are masked from 'package:base': 
## 
##  intersect, setdiff, setequal, union 

library(lubridate) 

## 
## Attaching package: 'lubridate' 

## The following object is masked from 'package:base': 
## 
##  date 

df1 <- read.table(
    text = " 
    Year Month Day Average 
    2013 8  28 2.3 
    2013 8  29 2.3 
    2013 8  30 1.7 
    2013 8  31 1.7 
    2014 8  7 3 
    2014 8  6 3 
    2014 8  8 3 
    2014 8  9 3 
    2014 9  11 5.8 
    2014 9  12 5.8 
    2014 9  13 5.8", 
header = T) 

df2 <- read.table(
    text = " 
    Year Month Day Average 
    2013 8  28 2.3 
    2013 8  29 0 
    2013 8  30 1.7 
    2013 8  31 0 
    2014 8  7 3 
    2014 8  6 0 
    2014 8  8 0 
    2014 8  9 0 
    2014 9  11 5.8 
    2014 9  12 0 
    2014 9  13 0", 
header = T) 

df3 <- read.table(
    text = " 
    Year Month Day Average 
    2013 8  28 2.3 
    2013 8  30 1.7 
    2014 8  7 3 
    2014 9  11 5.8", 
    header = T) 

df2 <- df1 %>% 
    mutate(date = ymd(paste(Year, Month, Day, sep = "-"))) %>% 
    arrange(date) %>% 
    mutate(is_consecutive_average = c(FALSE, diff(Average) == 0)) %>% 
    mutate(is_consecutive_day = c(FALSE, diff(date) == 1)) %>% 
    mutate(Average = Average * !(is_consecutive_average & is_consecutive_day)) %>% 
    select(-is_consecutive_average, -is_consecutive_day, -date) 

df2 

## Year Month Day Average 
## 1 2013  8 28  2.3 
## 2 2013  8 29  0.0 
## 3 2013  8 30  1.7 
## 4 2013  8 31  0.0 
## 5 2014  8 6  3.0 
## 6 2014  8 7  0.0 
## 7 2014  8 8  0.0 
## 8 2014  8 9  0.0 
## 9 2014  9 11  5.8 
## 10 2014  9 12  0.0 
## 11 2014  9 13  0.0 

df3 <- df2 %>% 
    filter(Average != 0) 

df3 

## Year Month Day Average 
## 1 2013  8 28  2.3 
## 2 2013  8 30  1.7 
## 3 2014  8 6  3.0 
## 4 2014  9 11  5.8 
+0

我的错误,现在修复。 – NGaffney

0

这里有一个data.table解决方案:

读入的数据

data <- readr::read_csv(
    text, 
    col_names = TRUE, 
    trim_ws = TRUE 
) 

library(data.table) 
setDT(data) 

转换的日期值一个更好的格式和排序

data[ , date := as.Date(paste0(Year, "-", Month, "-", Day)) ] 
setorder(data, date) 

创建一封新列日期和平均值

data[ , prev.date := shift(date, 1L, type = "lag") ] 
data[ , prev.average := shift(Average, 1L, type = "lag") ] 

根据您的标准标记应该创建新“组”的点。同时将第一个记录标记为新组的开始,因为我们可以假设它是。

data[ , group := 0L 
     ][ as.integer(date - prev.date) > 1L | 
     Average != prev.average, group := 1L 
     ][ 1L, group := 1L ] 

通过用零替换特定值的获取你的第一所期望的输出

data[ group != 1L, Average := 0 ] 
first.output <- data[ , .(date, Average) ] 
head(first.output, 3) 

     date Average 
1: 2013-08-28  2.3 
2: 2013-08-29  0.0 
3: 2013-08-30  1.7 

现在标记组独一无二的数字

data[ , group := cumsum(group) ] 

并通过聚集到最大的“平均得到你的第二输出“值(将是唯一不等于零的值)和最小”日期“值(该组中的第一个值):

second.output <- data[ , .(date = min(date), 
          Average = max(Average)), 
         by = group ][ , .(date, Average) ] 

head(second.output, 3) 
     date Average 
1: 2013-08-28  2.3 
2: 2013-08-30  1.7 
3: 2014-08-06  3.0 

注意:您可以通过简单地从first.output零“平均”值删除行可能会得到second.output,但它会删除任何组,其中“平均”真的是零,所以我觉得这个方法比较安全。