2016-10-05 95 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,但它會刪除任何組,其中「平均」真的是零,所以我覺得這個方法比較安全。