2013-12-10 11 views
2

У меня есть набор данных, который должен быть закрыт/обрезан и т. Д. На основе значений из другого набора данных. Оба набора данных имеют одинаковую структуру (имена столбцов и т. Д.).Как векторизовать эту операцию замены?

Что такое быстрый способ применения преобразований, хранящихся в другом наборе данных, к текущему набору данных?

Образец данных:

#generate sample data & set some values to NA 
#this is the dataset that has variables that need to be trimmed 
x1 <- data.frame(a=rep(11:20), b=rep(41:50)) 
x1[2,1] <- NA 
x1 

#a vector containing values to trim to (in this case, say 75th percentile) 
y1 <- apply(x1, 2, function(x) quantile(x, 0.75, na.rm=T)) 
y1 

#I am doing this inside a loop 
for (i in 1:ncol(x1)){ 
    x1[is.na(x1[[i]]),] <- y1[i]  #if missing, set to some value 

    x1[x1[[i]] > y1[i], i] <- y1[i] #if larger than 75th pctl, set to some value 
} 

x1 

Я уверен, что есть более быстрый Векторизованных способ сделать это. Я бы очень признателен за любые материалы.

ответ

1

Один вариант: написать логику как функцию, которая принимает вектор и значение:

myfun <- function(x, y) { 
    x[is.na(x)] <- y 
    x[x > y] <- y 
    return (x) 
} 

Затем использовать mapply, который будет рассматривать x1 как список столбцов (что-то есть):

mapply(myfun, x1, y1) 

И вы можете заставить его вернуться к data.frame, окружив его:

data.frame(mapply(myfun, x1, y1)) 

Можно также добавить SIMPLIFY=FALSE, если вы хотите ...


Согласно комментариям, Map является лучшим выбором здесь, так как это позволяет избежать некоторой типизации и, возможно, некоторые накладные расходы:

as.data.frame(Map(myfun, x1, y1)) 
+0

Да, вам нужно «SIMPLIFY = FALSE», или некоторые столбцы могут быть преобразованы в другой тип. Также обратите внимание, что 'as.data.frame (mapply (..., SIMPLIFY = FALSE))' эквивалентно более короткому 'as.data.frame (Map (...))'. – flodel

+0

Я всегда забываю о 'Карте' и' Сокращении'! – Justin

+0

Это прекрасно. Спасибо @Justin – user3053307

1

Вот другой вариант с использованием пакета data.table. data.table очень быстрый и мощный синтаксис, но недостатком является необходимость изучения нового синтаксиса.

library(data.table) 

x1 <- data.frame(a=rep(11:20), b=rep(41:50)) 
x1[2,1] <- NA 

# Convert data.frame to data.table. 
DT <- data.table(x1) 

# Put your desired operations into a function, for clarity/tidiness. 
update_vals <- function(x, prob=0.75) { 
    xcut <- quantile(x, probs=prob, na.rm=TRUE) 
    x[is.na(x) | x > xcut] <- xcut 
    return(x) 
} 

# Use lapply and data.table syntax to 'loop' over columns. 
DT2 = DT[, lapply(.SD, update_vals)] 
DT2 
#  a  b 
# 1: 11 41.00 
# 2: 18 42.00 
# 3: 13 43.00 
# 4: 14 44.00 
# 5: 15 45.00 
# 6: 16 46.00 
# 7: 17 47.00 
# 8: 18 47.75 
# 9: 18 47.75 
# 10: 18 47.75 
Смежные вопросы