Язык R: проблемы с вычислением "group by" или разделением с помощью пакета ff

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

"id" "birth_date"  "treatment"  "date_treatment"
123   2002-01-01    2            2011-01-03
123   2002-01-01    3            2011-10-03
124   2002-01-01    6            2009-11-07
124   2002-01-01    NA           NA
...   .....         ......       ........ 
1022  2007-01-01    4            2011-01-06

Я должен использовать пакет ff, чтобы иметь возможность работать с небольшим количеством оперативной памяти, поэтому ВСЕ процессы должны быть в функции ff. И я хочу знать, для каждого отдельного "идентификатора", который является минимальным "возрастом", когда он / она получил лечение = 2 или 4. Таким образом, это будет в каждом отдельном идентификаторе в общем коде:

if (обработка в c(2,4)), то min(date_treatment - birth_date)

Я только хочу сохранить эти минимальные "возрастные" данные и, возможно, идентификаторы.

Одним из решений является сделать:

age_c <- (data$date_treatment - data$birth_date)/365.25;
data$age_c <- age_c;
idx <- ffwhich( data, treatment %in% c(2,4) );
result  <- data[idx,];

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

age_fun <- function(x){ 
  min_ <- min.ff(x$age_c); 
  data.frame( age = min_);  
}

 result2 <- ffdfdply(x = data,
               split = data$id,
               FUN = function(x) age_fun(x),
               BATCHBYTES = 5000,
               trace=TRUE
 ); 

Что занимает много времени, а также дает много разных ошибок....

Любое решение этого?
Это общая проблема, которую легко реализовать в SAS или SQL, но я не нахожу правильную комбинацию в R. Поэтому общий вопрос будет следующим:

Как вычислить функции строки-столбца для одинаковых значений (групп) переменной (строки) в очень больших наборах данных???

Спасибо!!

1 ответ

Решение

ffdfdply - это функция, необходимая для решения вашего вопроса, но вы используете ее неправильно и неэффективно. Подумайте о ffdfdply как о получении в каждом FUN максимального количества данных R, которое вы можете поместить в ОЗУ, но при этом убедитесь, что вы получаете все свои данные по каждому идентификатору в ОЗУ (или, возможно, нескольким идентификаторам, если он умещается в ОЗУ).

Таким образом, брать BATCHBYTES 5000 довольно мало (у вас действительно есть только 5 килобайт оперативной памяти - я полагаю, нет - вы устанавливали R на Commodore с 90-х годов?) Далее, ваше FUN age_fun написано неправильно. Чтобы увидеть, что вы получаете в удовольствие, вы можете распечатать его. как в FUN=function(x){ print(head(x))); Икс}. В FUN вы получаете данные в оперативной памяти, поэтому вам не нужно использовать min.ff, min подойдет.

Также обратите внимание на замечание Джорана: вы получаете несколько идентификаторов в каждом чанке, если позволяет ваша оперативная память. Убедитесь, что ваш FUN использует стратегию разделения-применения-объединения или использует dply в FUN. И еще одно замечание, чтобы ускорить процесс. Вам действительно нужно передать весь FFDF. Вам нужны только столбцы, которые вы используете в функции и разделении. Так что ffdfdply(x = data[c("id","age_c","treatment")], split = ...) будет делать иначе, вы получите данные в ОЗУ, которые не нужны.

Короче говоря, что-то вроде этого поможет

require(doBy)
result2 <- ffdfdply(
  x = data[c("id","age_c","treatment")], split = data$id,
  FUN = function(x) summaryBy(age_c ~ id, data=subset(x, treatment %in% c(2,4)), FUN=min))

Если вы также хотите, чтобы ваши лица, которые не проходили лечение 2 и 4, делайте это.

require(doBy)
result2 <- ffdfdply(
  x = data[c("id","age_c","treatment")], split = data$id,
  FUN = function(x) {
   persons <- unique(x[, "id", drop=FALSE])
   result <- merge(
     persons,
     summaryBy(age_c ~ id, data=subset(x, treatment %in% c(2,4)), FUN=min),
     by.x="id", by.y="id", all.x=TRUE, all.y=FALSE
     )
   result
})
Другие вопросы по тегам