2016-10-05 5 views
0

Ich bin neu in R und ich habe die folgenden Daten (ein Beispiel) als CSV-Datei, und ich möchte alle doppelten Werte ersetzen, wenn sie an den aufeinanderfolgenden Tagen im gleichen Jahr und aufgetreten sind Monat für Null oder ein Brief. Ich muss nur einen Durchschnitt halten.Ersetzen Sie doppelte Werte mit mehreren Bedingungen in 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 

Das Ergebnis, das ich erwarte, ist so etwas wie dieses

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 

Auch würde ich die Zeilen löschen zu können, wie das die doppelten Werte haben, die wie folgt ersetzt:

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

Ich muss zwei Dateien haben, eine mit den doppelten Werten, die durch Null oder einen Buchstaben ersetzt werden, und eine andere hat nur die Mittelwerte ohne die doppelten Werte.

Vielen Dank im Voraus!

+0

Bitte denken Sie daran, 'dput' oder etwas ähnliches zu verwenden, um Ihre Daten zu teilen, es macht es viel einfacher zu helfen. – NGaffney

+1

An zwei aufeinanderfolgenden Tagen, wenn die Daten unterschiedlich sind, ist es sinnvoll, aber wenn es um die gleiche Zahl Runden, dann Sie es fallen lassen? Ich kenne die zugrunde liegenden Daten nicht, aber klingt, als würden Sie potenziell gute Daten wegwerfen. Plus, bestellt Ordnung? Sie behalten den früheren Durchschnitt für alle außer 2014/8/6. – r2evans

Antwort

0

Verwenden Sie dplyr für die data.frame-Manipulation, lubridate für Datum Manipulation und diff, um aufeinanderfolgende wiederholte Werte zu finden.

Beachten Sie, dass ich auch die Daten sortiert habe, um die früheste zu behalten, die es nicht genau mit der Beispiellösung übereinstimmt.

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

Mein Fehler, jetzt behoben. – NGaffney

0

Hier ist eine data.table Lösung:

Lesen der Daten

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

library(data.table) 
setDT(data) 

die Datumswerte ein schöneres Format konvertieren und sortieren

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

neue Spalten erstellen für frühere Datum und Durchschnittswerte

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

Markieren Sie die Punkte, auf denen eine neue "Gruppe" basierend auf Ihren Kriterien erstellt werden soll. Markieren Sie auch den allerersten Datensatz als Anfang einer neuen Gruppe, da wir davon ausgehen können, dass dies der Fall ist.

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

Ihre erste gewünschte Ausgabe erhalten, indem bestimmte Werte mit Nullen

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 

Jetzt ersetzen markieren die Gruppen als eindeutige Nummern

data[ , group := cumsum(group) ] 

Und Ihre zweite Ausgabe erhalten, indem auf Maximum „Average aggregieren "Wert (der der einzige Wert ungleich Null ist) und der Mindestwert" Datum "(der erste in dieser Gruppe):

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 

HINWEIS: Sie wahrscheinlich second.output durch einfaches Entfernen Zeilen mit einem Null „Average“ Wert aus den first.output bekommen können, aber es würde keine Gruppe entfernen, wo die „Average“ wirklich Null ist, so dass ich denke, dass dieses Verfahren sicherer ist.

Verwandte Themen