2016-12-09 6 views
1

У меня есть большой набор данных медицинских записей (20 миллионов строк). Я хочу создать новый столбец, который заполняется значением определенной строки внутри каждой группы.Для циклов: как избежать цикла, когда индекс используется для вызова нескольких разных значений столбцов?

Что выглядит Data Как

Данные выглядит следующим образом:

data <- data.frame(
     ICUSTAY_ID = c(1,1,5,5,5,5,5,6,6,6,6), 
     DATA = c(0,0,0,0,1,0,0,0,0,1,0), 
     OFFSET = c(-20,0,-1500, 150, 155, 159, 300, -2000, 30, 100, 120), 
     AA_FIRST = c(NA, NA, NA, NA, 1, NA, NA, NA,NA,1,NA), 
     LABRESULT = c(4, 5, 3.5, 4.1, NA, 3.0, 5.5, 2.1, 2.5, NA, 3.5)) 


      ID DATA OFFSET AA_FIRST LABRESULT 
      1 0 -20  NA  4.0 
      1 0  0  NA  5.0 
      5 0 -1500  NA  3.5 
      5 0 150  NA  4.1 
      5 1 155  1  NA 
      5 0 159  NA  3.0 
      5 0 300  NA  5.5 
      6 0 -2000  NA  2.1 
      6 0  30  NA  2.5 
      6 1 100  1  NA 
      6 0 120  NA  3.5 

То, что я хочу, чтобы данные Похожим

Для каждой группы идентификаторов, я хочу, чтобы найти строку в этой группе, которая имеет AA_FIRST = 1 (там будет только одна из этих групп ID), найдите значение OFFSET для этой строки, а затем вставьте это значение OFFSET в новый столбец с именем refOFFSET для все строки идентификатора , Я хочу, чтобы результат выглядеть следующим образом:

  ID DATA OFFSET AA_FIRST LABRESULT refOFFSET 
      1 0 -20  NA  4.0  NA 
      1 0  0  NA  5.0  NA 
      5 0 -1500  NA  3.5  155 
      5 0 150  NA  4.1  155 
      5 1 155  1  NA  155 
      5 0 159  NA  3.0  155 
      5 0 300  NA  5.5  155 
      6 0 -2000  NA  2.1  100 
      6 0  30  NA  2.5  100 
      6 1 100  1  NA  100 
      6 0 120  NA  3.5  100 

группа идентификаторов 5 имеет AA_FIRST = 1, соответствующее смещение 155, так что колонна refOFFSET для всех строк с ID = 5 были заселенных 155.

Группа ID 6 имеет значение AA_FIRST = 1, соответствующее СМЕЩЕНИЮ 100, поэтому столбец refOFFSET для всех строк с ID = 6 был заполнен 100.

Для группы идентификаторов необязательно должно быть AA_FIRST = 1. Это относится к группе ID 1. Группа ID 1 не имеет AA_FIRST = 1, поэтому refOFFSET является NA.

Не все идентификационные значения могут существовать. Например, идентификаторы № 2, 3 и 4 не существуют.

Мой текущий подход

Мой код, чтобы сделать это прямо сейчас состоит из для петель и если/еще заявления. Я хотел бы придумать векторный или применить форму. Мой для цикл занимает слишком много времени с 20 миллионами строк.

data$refOFFSET <- NA #initialize column called refOFFSET 

for (i in 1:length(data$ID)){ 
     if (!length(which(data$ID==(data$ID[i]) & data$AA_FIRST==1))) { #if it's integer0 
       next #go on to next i 
     }else{ 
       tmpval <- data$OFFSET[which(data$ID==(data$ID[i]) & data$AA_FIRST==1)]} 
     data$refOFFSET[i] <- tmpval #create column whose value is equal to the reference OFFSET for each ID (i.e. the OFFSET where AA_FIRST=1) 
} 

Вопрос

Кто-нибудь знает, как писать код выше в Векторизованных или применить форму? Все, что может ускорить вычисление? Спасибо!

Редактировать: мои воспроизводимые примеры данных и отображаемые исходные данные были немного разными. Я исправил это.

+0

Вы используете какую-то базу данных, такую ​​как SQL-Server? Потому что, если вы это сделаете, было бы намного проще – MVCNoob

+0

Да, я мог бы вернуться и повторно извлечь данные на SQL-сервере. Вышеупомянутые столбцы уже взяты из нескольких разных слияний таблиц, и как DATA, так и AA_FIRST исходят из вычислений, выполненных в R. Я думаю, что было бы проще попытаться работать с данными в R, чтобы избежать повторного выполнения этих вычислений в SQL, но если нет никакого хорошего способа сделать это в R, тогда я определенно был бы открыт для подхода SQL. Благодаря! –

ответ

0

Вы можете также подмножество для строк, где AA_FIRST == 1 и сохранить его в виде таблицы перекодировки (аналог словаря в Python), а затем матч на основе ID.

data<- data.frame(
    ID = c(1,1,5,5,5,5,5,6,6,6,6), 
    DATA = c(0,0,0,0,1,0,0,0,0,1,0), 
    OFFSET = c(-20,0,-1500, 150, 155, 159, 300, -2000, 30, 100, 120), 
    AA_FIRST = c(NA, NA, NA, NA, 1, NA, NA, NA, NA, 1, NA), 
    LABRESULT = c(4.0, 5.0, 3.5, 4.1, NA, 3.0, 5.5, 2.1, 2.5, NA, 3.5)) 

dict <- subset(data, data$AA_FIRST==1)[c("ID", "OFFSET")] 

data$refOFFSET <- dict[match(data$ID, dict$ID), 2] 
2

Мы можем попробовать с dplyr. Группируя данные на ICUSTAY_ID, мы находим индекс, который является минимальным для AA_FIRST=1 и использует соответствующее значение OFFSET для всей группы.

library(dplyr) 
data %>% 
    group_by(ICUSTAY_ID) %>% 
    mutate(refOFFSET = OFFSET[which.min(AA_FIRST == 1)]) 

# ICUSTAY_ID DATA OFFSET AA_FIRST LABRESULT refOFFSET 
# <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl> 
#1  1  0 -20  NA  4.0  NA 
#2  1  0  0  NA  5.0  NA 
#3  5  0 -1500  NA  3.5  155 
#4  5  0 150  NA  4.1  155 
#5  5  1 155  1  NA  155 
#6  5  0 159  NA  3.0  155 
#7  5  0 300  NA  5.5  155 
#8  6  0 -2000  NA  2.1  100 
#9  6  0  30  NA  2.5  100 
#10  6  1 100  1  NA  100 
#11  6  0 120  NA  3.5  100 
+0

Большое вам спасибо! Очень умное использование OFFSET [...]. Это именно тот тип ответа, на который я надеялся. Это прекрасно работает с приведенными мной примерами. Однако, когда я пытаюсь использовать свои реальные данные, я получаю сообщение об ошибке: _ «Ошибка: несовместимый размер (0), ожидающий 7 (размер группы) или 1» _ Ваш код работает нормально, если я его сменил на OFFSET [1 ] или OFFSET [AA_FIRST == 1]. Есть что-то о добавлении _which.min_, которое вызывает эту ошибку. Я не уверен, с чего начать его отладку. Любые идеи, которые могут вызывать ошибку? Еще раз спасибо! –

+0

@LinaColucci Было бы сложно отладить сообщение об ошибке без фактических данных. Можете ли вы поделиться подмножеством даты с использованием 'dput', который вызывает ошибку, чтобы ошибка воспроизводилась и на моем конце? –

+0

Привет Ронак: @ Кармен-Лай ниже нашел решение для этого, используя _match_ вместо _which.min_. Удаление второго столбца «1» из столбца AA_FIRST воспроизводит ошибку: структура (список (ICUSTAY_ID = c (1, 1, 5, 5, 5, 5, 5, 6, 6, 6, 6 ), DATA = c (0 , 0, 0, 0, 1, 0, 0, 0, 0, 1, 0), OFFSET = c (-20, 0, -1500, 150, 155, 159, 300, -2000, 30, 100, 120), AA_FIRST = c (NA, NA, NA, NA, 1, NA, NA, NA, NA, NA, NA), LABRESULT = c (4, 5, 3.5, 4.1, NA, 3, 5.5, 2.1, 2.5, NA, 3.5)) .Names = c ("ICUSTAY_ID", "DATA", "OFFSET", "AA_FIRST", "LABRESULT"), row.names = c (NA, -11L) class = "data.frame") –

1

Вы можете создать свою собственную функцию и использовать применяются так:

my_function<-function(input_vector){ 
    if(is.na(input_vector[4])){return(NA)} 
    if(input_vector[4]==1){ 
     return(input_vector[3]) 
    }else{retun(NA)} 
} 

data<- data.frame(
     ID = c(5,5,5,5,5,6,6,6,6), 
     DATA = c(0,0,1,0,0,0,0,1,0), 
     OFFSET = c(-1500, 150, 155, 159, 300, -2000, 30, 100, 120), 
     AA_FIRST = c(NA, NA, 1, NA, NA, NA,NA,1,NA), 
     LABRESULT = c(3.5, 4.1, NA, 3.0, 5.5, 2.1, 2.5, NA, 3.5)) 

ref_col=apply(data,1,my_function) 
data[,'refOFFSET']=ref_col 

refOFFSET_val_idx=which(!is.na(ref_col)) 
refOFFEST_lookup_df=data[refOFFSET_val_idx,c('ID','refOFFSET')] 
for(i in 1:nrow(refOFFEST_lookup_df)){ 
    ID_to_change_idx=which(data$ID==refOFFEST_lookup_df[i,'ID']) 
    data[ID_to_change_idx,'refOFFSET']=refOFFEST_lookup_df[i,'refOFFSET'] 
} 
0

Вот вариант использования data.table. Преобразуйте данные data.frame в 'data.table '(setDT(data)), сгруппированный по «ICUSTAY_ID», мы получаем индекс значения 1 в «AA_FIRST», чтобы получить соответствующее значение «OFFSET» и присвоить ему (:=) его «refOFFSET». Это должно быть очень эффективным, поскольку мы назначаем на место.

library(data.table) 
setDT(data)[, refOFFSET := OFFSET[match(1, AA_FIRST)], by = ICUSTAY_ID] 
data 
# ICUSTAY_ID DATA OFFSET AA_FIRST LABRESULT refOFFSET 
# 1:   1 0 -20  NA  4.0  NA 
# 2:   1 0  0  NA  5.0  NA 
# 3:   5 0 -1500  NA  3.5  155 
# 4:   5 0 150  NA  4.1  155 
# 5:   5 1 155  1  NA  155 
# 6:   5 0 159  NA  3.0  155 
# 7:   5 0 300  NA  5.5  155 
# 8:   6 0 -2000  NA  2.1  100 
# 9:   6 0  30  NA  2.5  100 
#10:   6 1 100  1  NA  100 
#11:   6 0 120  NA  3.5  100 
0

Использования match найти индекс, кажется, решить несовместимую ошибку размера вы упомянули в растворе Ронака шаха.

data %>% 
    group_by(ID) %>% 
    mutate(refOFFSET = OFFSET[match(TRUE, AA_FIRST==1)]) 

"For a logical vector x with both FALSE and TRUE values, which.min(x) and which.max(x) return the index of the first FALSE or TRUE, respectively, as FALSE < TRUE. However, match(FALSE, x) or match(TRUE, x) are typically preferred, as they do indicate mismatches."

http://stat.ethz.ch/R-manual/R-devel/library/base/html/which.min.html

0

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

foo <- data[! is.na(data$AA_FIRST),c('ID','OFFSET')] 
    colnames(foo) <- c("ID", "refOFFSET") 
    result <- merge(data, foo, on = "ID") 
+0

Мне нужно было изменить последнюю строку на 'result <- merge (tmp, foo, by =" ID ", all.x = T)', а затем он работает! –

 Смежные вопросы

  • Нет связанных вопросов^_^