Фильтровать фрейм данных по результатам от функции tapply

Я пытаюсь применить функцию tapply, которую я написал, для фильтрации набора данных. Вот образец кадра данных (df) ниже, чтобы описать, что я пытаюсь сделать.

Я хочу сохранить в моем фрейме данных строки, в которых значение df $ Cumulative_Time наиболее близко к значению 14. Он должен делать это для каждого уровня фактора в df $ ID (сохраняйте строку, ближайшую к значению 14 для каждого фактора ID).

ID  Date    Results TimeDiff    Cumulative_Time
A   7/10/2015   71  0   0
A   8/1/2015    45  20  20
A   8/22/2015   0   18  38
A   9/12/2015   79  17  55
A   10/13/2015  44  26  81
A   11/27/2015  98  37  118
B   7/3/2015    75  0   0
B   7/24/2015   63  18  18
B   8/21/2015   98  24  42
B   9/26/2015   70  30  72
C   8/15/2015   77  0   0
C   9/2/2015    69  15  15
C   9/4/2015    49  2   17
C   9/8/2015    88  2   19
C   9/12/2015   41  4   23
C   9/19/2015   35  6   29
C   10/10/2015  33  18  47
C   10/14/2015  31  3   50
D   7/2/2015    83  0   0
D   7/28/2015   82  22  22
D   8/27/2015   100 26  48
D   9/17/2015   19  17  65
D   10/8/2015   30  18  83
D   12/9/2015   96  51  134
D   1/6/2016    30  20  154
D   2/17/2016   32  36  190
D   3/19/2016   42  27  217

Я дошел до следующего:

spec_day = 14  # value I want to compare df$Cumulative_Time to


# applying function to calculate closest value to spec_day
    tapply(df$Cumulative_Time, df$ID, function(x) which(abs(x - spec_day) == min(abs(x - spec_day))))

Вопрос: как мне включить эту функцию tapply как средство для фильтрации моего фрейма данных df? Правильно ли я подхожу к этой проблеме или есть какой-то более простой способ решить эту проблему, которого я не вижу? Любая помощь будет оценена по достоинству - спасибо!


person soitgoes    schedule 31.05.2016    source источник
comment
Если вы хотите придерживаться базового языка R, вы можете взглянуть на split(df, df$ID), а затем с lapply использовать свой подход для получения индексов, соответствующих определенному идентификатору result <- lapply(mysplit, FUN=function(df){df[which()...,]}). Наконец, объедините все отфильтрованные данные с do.call("rbind", result). Я бы посоветовал изучить data.table вариантов   -  person Eric Lecoutre    schedule 31.05.2016
comment
Спасибо, @EricLecoutre! Я помню, как читал о split (), поэтому попробую и этот метод!   -  person soitgoes    schedule 31.05.2016


Ответы (2)


Вот как это можно сделать, обратите внимание, что я не использовал tapply:

spec_day <- 14
new_df <- do.call('rbind', 
            by(df, df$ID, 
            FUN = function(x) x[which.min(abs(x$Cumulative_Time - spec_day)), ]
              ))
new_df

  ID      Date Results TimeDiff Cumulative_Time
A  A  8/1/2015      45       20              20
B  B 7/24/2015      63       18              18
C  C  9/2/2015      69       15              15
D  D 7/28/2015      82       22              22

which.min (и его брат which.max) - очень полезная функция.

person bouncyball    schedule 31.05.2016
comment
Спасибо, @bouncyball! Думаю, я понимаю which.min - спасибо, что указали мне на эту функцию, а также познакомили меня с другим подходом к этой проблеме! - person soitgoes; 31.05.2016

Вот более краткая и быстрая альтернатива с использованием data.table:

library(data.table)
setDT(df)[, .SD[which.min(abs(Cumulative_Time - 14))], by = ID]
#   ID      Date Results TimeDiff Cumulative_Time
#1:  A  8/1/2015      45       20              20
#2:  B 7/24/2015      63       18              18
#3:  C  9/2/2015      69       15              15
#4:  D 7/28/2015      82       22              22
person mtoto    schedule 31.05.2016
comment
Спасибо, @mtoto! Мне нравится лаконичность этого. Также довольно интуитивно понятно, что делает код! - person soitgoes; 01.06.2016