2013-02-26 5 views
5

Мне очень неприятно задавать два вопроса подряд, но это то, над чем я не могу окутать голову. Так скажем, у меня есть кадр данных, следующий образом:Вычитание по разным строкам и столбцам и разделение по группам

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 

Можно ли в R взять разницу между предыдущим днем ​​подряда (и только в предыдущий день, а не предыдущий результат) вечернее значение 1 строка и утреннее значение другой строки для каждой группы пользователей? Поэтому мои желаемые результаты были бы такими.

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 

Все, что я хочу, чтобы это сделать, это принять утреннее значение и вычесть его из вечернего значения предыдущего дня подряда для каждой группы пользователей. Как вы можете видеть, некоторые части моего фрейма данных содержат значения NA в утренних и вечерних столбцах, кроме того, не все даты находятся в последовательном порядке для каждого другого пользователя, поэтому, естественно, следует назначить NA.

Я пробовал искать Google, но не было информации о возможности применения функций к различным строкам для каждой группы строк в разных столбцах (если это имеет смысл).

Мои попытки включают в себя множество вариантов этого.

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

С другой стороны, любая помощь будет принята с благодарностью. Благодарю.

+2

Вы действительно должны отметить использование '#' в именах столбцов ... – juba

ответ

4

Примечание: Входные данные вы показываете и выходные данные не совпадают. Существует NA, который заменяется на 10 на выходе, а последняя дата - 2/14/11 на входе и 2/22/11.

Я предположил, что выходные данные являются исходными данными для создания этого ответа в соответствии с вашим результатом.

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 

@ редактировать user1342086 (то был отклонен, но был прав на самом деле):

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

, кажется, заботиться о группировке по "User".

+0

Хороший улов, я думаю, что я только что его исправил. Но да, я менял его, чтобы соответствовать конкретным сценариям. Но спасибо, я попробую это решение завтра. – rj2700

+0

Учтите, что это будет работать, только если даты всегда в хронологическом порядке для каждого пользователя и что данные каждого пользователя находятся в последовательных строках. –

+0

Как отмечает @Geektrader, это не заботится и о группе «Пользователь». Далее я предоставлю модифицированное решение. Оскар, хотя это правда, 'порядок' на столбцах' User' и 'Measure_Date' будет намного проще. – Arun

4

Слепой первый выстрел (непроверенный). Опирается на фрейм данных, уже отсортированный по User и Date.

#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) Это аккуратно. OP будет заменять 'diff (Date)' на 'diff (as.Date (as.character (Measure_Date), format ="% m /% d /% Y "))' потому что он загружается как «фактор» , – Arun

+0

Спасибо, я попробую это решение завтра. – rj2700

+1

Наряду с diff (Date) == 1 вам также нужно проверить diff (User) == 0 –

2

Я использовал plyr, поэтому обязательно установите его. Это решение должно работать, даже если пользовательские данные смешиваются (, т. Е. не в последовательных строках), а даты не находятся в хронологическом порядке.

# 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 
     }) 
Смежные вопросы