Язык 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
})