2014-01-04 4 views
2

Я хотел бы вернуть матрицу/data.frame каждую строку, содержащую аргументы и содержимое файла.R - хранить функции в data.frame

Однако может быть много файлов, поэтому я бы предпочел, чтобы я мог загрузить файл лениво, поэтому файл читается только в том случае, если запрашивается фактический контент. Функция ниже загружает файлы активно, если as.func=F.

Было бы идеально, если бы оно могло лениво загрузить их, но было бы также приемлемо, если вместо контента возвращается функция, которая будет читать содержимое.

Я могу выполнять функции, которые читают содержимое (см. Ниже с as.func=T), но по какой-то причине я не могу поместить это в data.frame для возврата.

load_parallel_results <- function(resdir,as.func=F) { 
    ## Find files called .../stdout                                            
    stdoutnames <- list.files(path=resdir, pattern="stdout", recursive=T); 
    ## Find files called .../stderr                                            
    stderrnames <- list.files(path=resdir, pattern="stderr", recursive=T); 
    if(as.func) { 
    ## Create functions to read them                                           
    stdoutcontents <- 
     lapply(stdoutnames, function(x) { force(x); return(function() { return(paste(readLines(paste(resdir,x,sep="/")),collapse="\n")) }) }); 
    stderrcontents <- 
     lapply(stderrnames, function(x) { force(x); return(function() { return(paste(readLines(paste(resdir,x,sep="/")),collapse="\n")) }) }); 
    } else { 
    ## Read them                                                
    stdoutcontents <- 
     lapply(stdoutnames, function(x) { return(paste(readLines(paste(resdir,x,sep="/")),collapse="\n")) }); 
    stderrcontents <- 
     lapply(stderrnames, function(x) { return(paste(readLines(paste(resdir,x,sep="/")),collapse="\n")) }); 
    } 
    if(length(stdoutnames) == 0) { 
    ## Return empty data frame if no files found                                        
    return(data.frame()); 
    } 

    ## Make the columns containing the variable values                                       
    m <- matrix(unlist(strsplit(stdoutnames, "/")),nrow = length(stdoutnames),byrow=T); 
    mm <- as.data.frame(m[,c(F,T)]); 
    ## Append the stdout and stderr column                                          
    mmm <- cbind(mm,unlist(stdoutcontents),unlist(stderrcontents)); 
    colnames(mmm) <- c(strsplit(stdoutnames[1],"/")[[1]][c(T,F)],"stderr"); 
    ## Example:                                                 
    ## parallel --results my/res/dir --header : 'echo {};seq {myvar1}' ::: myvar1 1 2 ::: myvar2 A B                            

    ## > load_parallel_results("my/res/dir")                                          
    ##  myvar1 myvar2 stdout  stderr                                          
    ## [1,] "1" "A" "1 A\n1" ""                                           
    ## [2,] "1" "B" "1 B\n1" ""                                           
    ## [3,] "2" "A" "2 A\n1\n2" ""                                           
    ## [4,] "2" "B" "2 B\n1\n2" ""                                           
    return(mmm); 
} 

фон

GNU Parallel имеет --results вариант, который хранит выход в структурированном виде. Если есть 1000000 выходных файлов, их может быть сложно управлять. R хорош для этого, но было бы очень медленно, если бы вам нужно было прочитать все 1000000 файлов, чтобы получить те, где аргумент 1 = «Foo» и аргумент 2 = «Bar».

+0

Вы можете иметь функции в матрице, например, 'Foo <- матрица (список (средний С.Д.,' + ', список), 2,2). Но я не думаю, что вам это понадобится, если не считать особого случая. Почему вы не можете хранить имена файлов в матрице или фрейме данных и использовать их при необходимости? – lebatsnok

+0

1e6 файлов - это много файлов, что делает много дорогостоящих 'stat()' вызовов и т. Д. Возможно, посредничество в очереди проще? Мне повезло с redis и R доступом через пакет rredis. –

ответ

2

К сожалению, я не думаю, что вы можете сохранить функцию в столбце data.frame. Но вы можете сохранить текст, снятый с охраны, и оценить его при необходимости:

например.

myFunc <- function(x) { print(x) } 
# convert the function to text 
funcAsText <- deparse(myFunc) 

# convert the text back to a function 
newMyFunc <- eval(parse(text=funcAsText)) 

# now you can use the function newMyFunc exactly like myFunc 
newMyFunc("foo") 

> [1] "foo" 

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

0

Вы можете использовать 2D-списки для хранения ваших функций. Очевидно, что вы потеряете некоторые из проверок, которые Вы получаете с ДХ, но это все дело здесь:

> funs <- c(replicate(5, function(x) NULL), replicate(5, function(y) TRUE)) 
> names <- as.list(letters[1:10]) 
> # df doesn't work 
> df <- data.frame(names=names) 
> df.2 <- cbind(df, funs) 
Error in as.data.frame.default(x[[i]], optional = TRUE) : 
    cannot coerce class ""function"" to a data.frame 
# but 2d lists do 
> lst.2d <- cbind(funs, names) 
> lst.2d[2, 1] 
$funs 
function (x) 
    NULL 
> lst.2d[6, 1] 
$funs 
function (y) 
    TRUE 
Смежные вопросы