добавить столбцы во фрейм данных, используя foreach и% dopar% - PullRequest
4 голосов
/ 27 октября 2011

В Revolution R 2.12.2 в Windows 7 и Ubuntu 64-bit 11.04 у меня есть фрейм данных с более чем 100K строк и более 100 столбцов, и я получаю ~ 5 столбцов (sqrt, log, log10 и т. Д.) Для каждого изисходные столбцы и добавьте их в тот же фрейм данных.Без параллелизма с использованием foreach и% do% это работает нормально, но медленно.Когда я пытаюсь распараллелить его с foreach и% dopar%, он не будет обращаться к глобальной среде (чтобы предотвратить состояние гонки или что-то в этом роде), поэтому я не могу изменить фрейм данных, потому что объект фрейма данных «не найден».

Мой вопрос как я могу сделать это быстрее ?Другими словами, как распараллелить либо столбцы, либо преобразования?

Упрощенный пример:

require(foreach)    
require(doSMP)
w <- startWorkers()
registerDoSMP(w)

transform_features <- function()
{    
    cols<-c(1,2,3,4) # in my real code I select certain columns (not all)

    foreach(thiscol=cols, mydata) %dopar% { 
        name <- names(mydata)[thiscol]
        print(paste('transforming variable ', name))
        mydata[,paste(name, 'sqrt', sep='_')] <<- sqrt(mydata[,thiscol])
            mydata[,paste(name, 'log', sep='_')] <<- log(mydata[,thiscol])
    }
}


n<-10 # I often have 100K-1M rows
mydata <- data.frame(
    a=runif(n,1,100),
    b=runif(n,1,100),
    c=runif(n,1,100),
    d=runif(n,1,100)
    )

ncol(mydata) # 4 columns

transform_features()

ncol(mydata) # if it works, there should be 8

Обратите внимание, что если вы измените% dopar% на% do%, он будет работать нормально

Ответы [ 3 ]

2 голосов
/ 27 октября 2011

Попробуйте оператор := в data.table, чтобы добавить столбцы по ссылке.Вам понадобится with=FALSE, чтобы вы могли выполнить вызов paste на LHS :=.

См. Когда мне следует использовать оператор: = в data.table?

1 голос
/ 27 октября 2011

Есть два способа справиться с этим:

  1. Выполните цикл по каждому столбцу (или, еще лучше, по подмножеству столбцов) и примените преобразования для создания временного фрейма данных, верните его, а затем выполните cbind списка фреймов данных, @ Генри предложил.

  2. Зацикливание преобразований, примените каждое к кадру данных, а затем верните кадры данных преобразования cbind и продолжите.

Лично я склонен делать подобные вещи, создавая объект bigmatrix (в памяти или на диске, используя пакет bigmemory), и вы можете получить доступ ко всем столбцам в разделяемой памяти. Просто предварительно выделите столбцы, которые вы будете заполнять, и вам не нужно будет делать это пост * hoc cbind. Я склонен делать это на диске. Просто запустите flush(), чтобы убедиться, что все записано на диск.

1 голос
/ 27 октября 2011

Может быть проще, если бы вы сделали что-то вроде

n<-10
mydata <- data.frame(
    a=runif(n,1,100),
    b=runif(n,1,100),
    c=runif(n,1,100),
    d=runif(n,1,100)
    )

mydata_sqrt <- sqrt(mydata)  
colnames(mydata_sqrt) <- paste(colnames(mydata), 'sqrt', sep='_')

mydata <- cbind(mydata, mydata_sqrt)

, производящее что-то вроде

> mydata
           a         b         c        d   a_sqrt   b_sqrt   c_sqrt   d_sqrt
1  29.344088 47.232144 57.218271 58.11698 5.417018 6.872565 7.564276 7.623449
2   5.037735 12.282458  3.767464 40.50163 2.244490 3.504634 1.940996 6.364089
3  80.452595 76.756839 62.128892 43.84214 8.969537 8.761098 7.882188 6.621340
4  39.250277 11.488680 38.625132 23.52483 6.265004 3.389496 6.214912 4.850240
5  11.459075  8.126104 29.048527 76.17067 3.385126 2.850632 5.389669 8.727581
6  26.729365 50.140679 49.705432 57.69455 5.170045 7.081008 7.050208 7.595693
7  42.533937  7.481240 59.977556 11.80717 6.521805 2.735186 7.744518 3.436157
8  41.673752 89.043099 68.839051 96.15577 6.455521 9.436265 8.296930 9.805905
9  59.122106 74.308573 69.883037 61.85404 7.689090 8.620242 8.359607 7.864734
10 24.191878 94.059012 46.804937 89.07993 4.918524 9.698403 6.841413 9.438217
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...