2015-12-27 12 views
9

Używam dplyr do zamiany value z NA, jeśli warunek jest spełniony, ale umieszcza NA w miejscu, gdzie nie powinien być.Dlaczego dplyr usuwa wartości nie spełnione przez warunek?

dput:

df <- structure(list(id = c("USC00231275", "USC00231275", "USC00231275", 
"USC00231275", "USC00231275", "USC00231275", "USC00231275", "USC00231275", 
"USC00231275", "USC00231275"), element = c("TMAX", "TMIN", "TMAX", 
"TMIN", "TMAX", "TMIN", "TMAX", "TMIN", "TMAX", "TMIN"), year = c(1937, 
1937, 1937, 1937, 1937, 1937, 1937, 1937, 1937, 1937), month = c(5, 
5, 5, 5, 5, 5, 5, 5, 5, 5), day = c(1, 1, 2, 2, 3, 3, 4, 4, 5, 
5), date = structure(c(-11933, -11933, -11932, -11932, -11931, 
-11931, -11930, -11930, -11929, -11929), class = "Date"), value = c(0, 
53.96, 68, 44.96, 62.06, 53.96, 73.04, 53.96, 69.08, 50)), .Names = c("id", 
"element", "year", "month", "day", "date", "value"), row.names = c(NA, 
10L), class = "data.frame") 

data.frame (Uwaga: warunek jest spełniony jedynie w wierszu 1, 2)

  id element year month day  date value 
1 USC00231275 TMAX 1937  5 1 1937-05-01 0.00 
2 USC00231275 TMIN 1937  5 1 1937-05-01 53.96 
3 USC00231275 TMAX 1937  5 2 1937-05-02 68.00 
4 USC00231275 TMIN 1937  5 2 1937-05-02 44.96 
5 USC00231275 TMAX 1937  5 3 1937-05-03 62.06 
6 USC00231275 TMIN 1937  5 3 1937-05-03 53.96 
7 USC00231275 TMAX 1937  5 4 1937-05-04 73.04 
8 USC00231275 TMIN 1937  5 4 1937-05-04 53.96 
9 USC00231275 TMAX 1937  5 5 1937-05-05 69.08 
10 USC00231275 TMIN 1937  5 5 1937-05-05 50.00 

dplyr

df %>% 
    group_by(date) %>% 
    mutate(
    value = if(value[element == 'TMIN'] >= value[element == 'TMAX']) 
     as.numeric(NA) else value 
) 

      id element year month day  date value 
     (chr) (chr) (dbl) (dbl) (dbl)  (date) (dbl) 
1 USC00231275 TMAX 1937  5  1 1937-05-01 NA 
2 USC00231275 TMIN 1937  5  1 1937-05-01 NA 
3 USC00231275 TMAX 1937  5  2 1937-05-02 68.00 
4 USC00231275 TMIN 1937  5  2 1937-05-02 44.96 
5 USC00231275 TMAX 1937  5  3 1937-05-03 NA 
6 USC00231275 TMIN 1937  5  3 1937-05-03 NA 
7 USC00231275 TMAX 1937  5  4 1937-05-04 73.04 
8 USC00231275 TMIN 1937  5  4 1937-05-04 53.96 
9 USC00231275 TMAX 1937  5  5 1937-05-05 69.08 
10 USC00231275 TMIN 1937  5  5 1937-05-05 50.00 

Należy zauważyć, że gdy tylko wiersze powinien zmienić są 1 i 2, ale dplyr zmieniono wiersze 5 i 6, mimo że warunki nie zostały spełnione.

+0

Wow, patrzył na to przez chwilę, spróbuj tego: 'z <- df %>% group_by (rok, miesiąc, dzień)%>% mutacji (test = diff (value))%>% ungroup%>% mutate (value2 = ifelse (test> 0, NA, as.numeric (value))) "To działa, ale jeśli usuniesz rozgrupowanie, nagle NA ponownie wróci ... Jestem nieco zdumiony – Shape

+0

@Shape Tak, to było z twojej poprzedniej odpowiedzi i wydaje się nie działać na oryginalnym zbiorze danych. Bardzo dziwne, pomyślałem. Dzięki! – Vedda

+1

To jest kwestia widoczna z użyciem NA jako wartości zastępczej, spójrz na to: 'df%>% group_by (rok, miesiąc, dzień)%>% mutate (value = if (value [element == 'TMIN'] > = wartość [element == 'TMAX']) 1 wartość inna) 'działa. Ale NA powoduje problemy, brzmi to jak błąd – Shape

Odpowiedz

1

Poniższy kod powinien robić to, co staramy się robić

df %>% 
    group_by(date) %>% 
    mutate(new_value = ifelse(((value[element == 'TMIN'] >= value[element == 'TMAX']) & element=='TMIN'), NA, value)) %>% 
    ungroup 

Na pytanie, czy jest to błąd czy nie, nie sądzę, że jest. Patrząc na dane tylko dla jednego roku, gdzie Tmin> = TMAX, dostępne są następujące

df %>% 
    filter(date == '1937-05-01') %>% 
    mutate(res = (value[element == 'TMIN'] >= value[element == 'TMAX'])) %>% 
    mutate(new_value = ifelse((res & element=='TMIN'), NA, value)) 

      id element year month day  date value res new_value 
1 USC00231275 TMAX 1937  5 1 1937-05-01 0.00 TRUE   0 
2 USC00231275 TMIN 1937  5 1 1937-05-01 53.96 TRUE  NA 

konstrukt value[element == 'TMIN'] >= value[element == 'TMAX']) zawsze będzie prawdziwe jak widać w kolumnie res. Poniższy kod nieco to załamuje, mam nadzieję, że wyjaśnię (mam nadzieję).

### Just looking at one date 
> df2 <- df %>% filter(date == '1937-05-01') 
> df2 
      id element year month day  date value 
1 USC00231275 TMAX 1937  5 1 1937-05-01 0.00 
2 USC00231275 TMIN 1937  5 1 1937-05-01 53.96 

### This comparison will be recycled for every element in the group, 
### so it will always be TRUE or always FALSE. 
> c(df2$value[df2$element == 'TMIN'], df2$value[df2$element == 'TMAX']) 
[1] 53.96 0.00 

Ponieważ istnieje jedno porównanie dla całej grupy, zawsze będą widzieć PRAWDA lub zawsze FAŁSZ.

Kod, który daje poprawny wynik pokazuje porównanie można zdobyć wokół.

Jednym z możliwych rozwiązań końcowy może być:

df %>% 
    group_by(date) %>% 
    mutate(value = ifelse(((value[element == 'TMIN'] >= value[element == 'TMAX']) & element=='TMIN'), NA, value)) %>% 
    ungroup 
+0

Więc podczas gdy zgadzam się, że ifelse może ominąć to, pojedyncza PRAWDA lub fałsz był zamiarem oryginalnego kodu. Wynikiem jest wykonanie pojedynczej operacji dla każdej grupy, na podstawie dwóch wyszukiwań, a nie wielokrotnych, wektoryzowanych porównań. (Jest to szczególnie ważne, jeśli twoje długie dane mają więcej czynników niż "a" i "b", ale nadal chcesz uwzględnić wszystkie dane grupy). Kiedy zwracana jest jedna PRAWDA/FAŁSZ, wartości są zazwyczaj mnożone. Jest to coś, co NA powinno robić tak dobrze, jak każdą inną wartość. – Shape

Powiązane problemy