2013-02-26 16 views
5

Naprawdę nienawidzę zadawać dwóch pytań z rzędu, ale jest to coś, czego nie mogę objąć. Więc powiedzmy, że mam ramki danych, w następujący sposób:Odejmowanie w różnych wierszach i kolumnach i oddzielone przez grupę

df 
    Row# User Morning  Evening  Measure Date 
    1 1   NA   NA   2/18/11 
    2 1   50   115   2/19/11 
    3 1   85   128   2/20/11 
    4 1   62   NA   2/25/11 
    5 1   48   100.8  3/8/11 
    6 1   19   71   3/9/11 
    7 1   25   98   3/10/11 
    8 1   NA   105   3/11/11 
    9 2   48   105   2/18/11 
    10 2   28   203   2/19/11 
    11 2   35   80.99  2/21/11 
    12 2   91   78.25  2/22/11 

Czy jest możliwe w R wziąć różnicę między poprzednim dzień z rzędu (i tylko poprzedniego dnia, a nie poprzedni wynik) wartość wieczorną 1 wiersz i wartość poranna innego rzędu dla każdej grupy użytkowników? Tak więc moje pożądane rezultaty byłyby takie.

df 
    Row# User Morning  Evening  Date  Difference 
    1  1  NA   NA  2/18/11  NA 
    2  1  50   115  2/19/11  NA 
    3  1  85   129  2/20/11  30 
    4  1  62   NA  2/25/11  NA 
    5  1  48   100.8  3/8/11   NA 
    6  1  19   71  3/9/11   81.8 
    7  1  25   98  3/10/11  46 
    8  1  10   105  3/11/11  88 
    9  2  48   105  2/18/11  NA 
    10  2  28   203  2/19/11  77 
    11  2  35   80.99  2/21/11  NA 
    12  2  91   78.25  2/22/11  -10.01 

Wszystko czego chcę to zrobić, to przyjąć wartość rano i odjąć go od wartości wieczorem poprzedniego rzędu dzień dla każdej grupy użytkowników. Jak widać, niektóre części mojej ramki danych zawierają wartości NA w porannych i wieczornych kolumnach, ponadto nie wszystkie daty są w kolejnej kolejności dla każdego innego użytkownika, więc naturalnie NA powinna zostać przypisana.

Próbowałem wyszukiwać google, ale nie było wiele informacji na temat możliwości zastosowania funkcji do różnych wierszy dla każdej grupy wierszy w różnych kolumnach (jeśli ma to jakiś sens).

Moje próby obejmują wiele odmian tego.

df$Difference<-ave((df$Morning,df$Evening), 
        df$User, 
        FUN=function(x){ 
         c('NA',diff(df$Evening-df$Morning)),na.rm=T 
        }) 

Ponownie, każda pomoc będzie bardzo ceniona. Dzięki.

+2

Naprawdę powinni pamiętać użyć '#' w swoich nazwach kolumn ... – juba

Odpowiedz

4

Uwaga: Dane wejściowe można pokazać, a dane wyjściowe nie są takie same. Istnieje NA, który jest zastępowany przez 10 na wyjściu, a ostatnia data to 2/14/11 na wejściu i 2/22/11 na wyjściu.

Zakładałem, że dane wyjściowe będą oryginalnymi danymi, aby utworzyć tę odpowiedź w celu dopasowania do wyniku.

df$Diff <- c(NA, head(df$Evening, -1) - tail(df$Morning, -1)) 
df$Diff[which(c(0, diff(as.Date(as.character(df$Measure_Date), 
       format="%m/%d/%Y"))) != 1)] <- NA 

> df 

# Row User Morning Evening Measure_Date Diff 
# 1 1 1  NA  NA  2/18/11  NA 
# 2 2 1  50 115.00  2/19/11  NA 
# 3 3 1  85 128.00  2/20/11 30.00 
# 4 4 1  62  NA  2/25/11  NA 
# 5 5 1  48 100.80  3/8/11  NA 
# 6 6 1  19 71.00  3/9/11 81.80 
# 7 7 1  25 98.00  3/10/11 46.00 
# 8 8 1  10 105.00  3/11/11 88.00 
# 9 9 2  48 105.00  2/18/11  NA 
# 10 10 2  28 203.00  2/19/11 77.00 
# 11 11 2  35 80.99  2/21/11  NA 
# 12 12 2  91 78.25  2/22/11 -10.01 

@ edit user1342086'S (który został odrzucony, ale rzeczywiście miał rację):

df$Diff[which(diff(df$User) != 0)] <- NA 

wydaje się zająć grupa przez "użytkownika".

+0

Dobry połów, myślę, że właśnie to naprawiłem. Ale tak, zmieniłem go tak, by pasował do konkretnych scenariuszy. Ale dzięki, wypróbuję to rozwiązanie jutro. – rj2700

+0

Należy pamiętać, że będzie to działać tylko wtedy, gdy daty są zawsze chronologiczne dla każdego użytkownika, a dane każdego użytkownika są w kolejnych wierszach. –

+0

Jak wspomina @Geektrader, nie zajmuje się również grupą "User". Dostarczę zmodyfikowane rozwiązanie później. Oscar, o ile to prawda, "zamówienie" w kolumnach 'User' i' Measure_Date' będzie o wiele prostsze. – Arun

4

Niewidomy pierwszy strzał (nietestowany). Opiera się na ramce danych, która jest już posortowana według użytkownika i daty.

#if necessary, transform your dates from factor to Date 
df$Date <- as.Date(levels(df$Date)[df$Date],format="%m/%d/%y") 

df <- within(df, 
    Difference <- ifelse(c(NA,diff(Measure_Date)) == 1 & diff(User) == 0, 
    c(NA,head(Evening,-1)) - Morning, NA 
) 
) 
+1

(+1) Jest schludny. OP będzie musiał zastąpić 'diff (Date)' z 'diff (as.Date (as.character (Measure_Date), format ="% m /% d /% Y "))' ponieważ jest załadowany jako "czynnik" . – Arun

+0

Dzięki, wypróbuję to rozwiązanie jutro. – rj2700

+1

Wraz z diff (Date) == 1 musisz również sprawdzić diff (User) == 0 –

2

Użyłem plyr, więc upewnij się, że masz zainstalowany. To rozwiązanie powinno działać, nawet jeśli dane użytkownika są mieszane (, tj. nie w kolejnych wierszach), a daty nie są chronologiczne.

# Your example data, as you should post it for us to use 
df <- 
structure(list(User = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 
2L, 2L), Morning = c(NA, 50L, 85L, 62L, 48L, 19L, 25L, NA, 48L, 
28L, 35L, 91L), Evening = c(NA, 115, 128, NA, 100.8, 71, 98, 
105, 105, 203, 80.99, 78.25), Measure_Date = structure(c(1L, 
2L, 3L, 5L, 9L, 10L, 6L, 7L, 1L, 2L, 4L, 8L), .Label = c("2/18/11", 
"2/19/11", "2/20/11", "2/21/11", "2/25/11", "3/10/11", "3/11/11", 
"3/14/11", "3/8/11", "3/9/11"), class = "factor")), .Names = c("User", 
"Morning", "Evening", "Measure_Date"), class = "data.frame", row.names = c(NA, 
-12L)) 

# As already stated by Arun, you need the date as class Date 
df$Measure_Date <- as.Date(df$Measure_Date, format='%m/%d/%y') 


# Use plyr to procces the dataframe by user 
library(package=plyr) 
ddply(.data=df, .variables='User', 
     .fun=function(x){ 
     # Complete sequence of dates for each user 
     tdf <- data.frame(Measure_Date=seq(from=min(x$Measure_Date), 
              to=max(x$Measure_Date), 
              by='1 day')) 

     # Merge to fill in NAs for unused dates 
     tdf <- merge(tdf, x, all=TRUE) 

     # Put desired values side by side 
     tdf$Evening <- c(NA, tdf$Evening[-length(tdf$Evening)]) 

     # Diference 
     tdf$Difference <- tdf$Evening - tdf$Morning 

     # Return desired value to original data 
     tdf <- tdf[,c('Measure_Date', 'Difference')] 
     x <- merge(x, tdf) 
     x 
     }) 
Powiązane problemy