Как поместить цикл в функцию Саппли, чтобы создать подмножество для нескольких участников? - PullRequest
0 голосов
/ 09 июня 2018

Буду признателен за помощь в решении следующей проблемы:

У меня есть несколько огромных лог-файлов (> 1.000.000 записей каждый), которые содержат несколько строк (строк), которые представляют для меня особый интерес.Поэтому я хочу создать подмножество, содержащее только эти строки, но я хочу записать результат в матрицу, содержащую информацию для более чем одного файла журнала / участника.Поэтому я создал короткую строку кода, чтобы: 1. создать подмножество и 2. запустить его в цикле, чтобы сделать это не только для одного из файлов журнала, но и для всех них.

  Result <- subset(df, df$columnOfInterest== "interestingCondition1" | df$columnOfInterest== "interestingCondition2" | df$columnOfInterest== "interestingCondition3")$columnOfInterest
  View(Result)

1
interestingCondition1
2
interestingCondition1
3
interestingCondition2
4
interestingCondition1
5
interestingCondition1
6
interestingCondition3
7
interestingCondition2
8
interestingCondition1
9
interestingCondition1
10
interestingCondition1

Embededв цикл:

WrongResult <- matrix(data=NA,nrow=TrialNumber, ncol=length(ListOfFiles))
vpncount <- 1
for (v in ListOfFiles){

  df<- read.delim(v, header = TRUE, sep='\t')
  WrongResult[,vpncount] <- subset(df, df$columnOfInterest== "interestingCondition1" | df$columnOfInterest== "interestingCondition2" | df$columnOfInterest== "interestingCondition3")$columnOfInterest

vpncount <- vpncount+1

}

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

Кто-нибудь знает, почему это происходит и как это исправить?Любая помощь очень ценится!

РЕДАКТИРОВАТЬ:

Я попытался создать пример фрейма данных.Первая строка кода (включая переменную Results) работает так, как я хочу.Он фильтрует мой фрейм данных по строкам моего columnOfInterest и помещает их в новую матрицу.Но если я пытаюсь запустить его в цикле для более чем одного кадра данных, я продолжаю сталкиваться с ошибками:

df <- data.frame(
  X = sample(1:10),
  columnOfInterest= sample(c("interestingCondition1", "interestingCondition2", "interestingCondition3", "NotinterestingCondition1"), 10, replace = TRUE)
)

View(df)

Result <- subset(df, df$columnOfInterest== "interestingCondition1" | df$columnOfInterest== "interestingCondition2" | df$columnOfInterest== "interestingCondition3")$columnOfInterest
View(Result)

WrongResult <- matrix(data=NA,nrow=280, ncol=20)
vpncount <- 1
for (v in 1:20){

  df<- read.delim(v, header = TRUE, sep='\t')
  WrongResult[,vpncount] <- subset(df, df$columnOfInterest== "interestingCondition1" | df$columnOfInterest== "interestingCondition2" | df$columnOfInterest== "interestingCondition3")$columnOfInterest

  vpncount <- vpncount+1

}

View(WrongResult)

Ответы [ 3 ]

0 голосов
/ 09 июня 2018

В области Tidyverse при обработке одного фрейма данных вы хотите filter(), а затем select() исходных данных и для удобства добавьте, используя mutate(), имя файла.Хороший способ фильтрации, когда есть несколько возможных значений, использует %in%.Так что

library(tidyverse)

process_1_df <- function(df, id, condition)
    select(df, columnOfInterest) %>%                 # only interesting column
        filter(columnOfInterest %in% condition) %>%  # specific rows
        mutate(id = id)                              # add identifier

condition <- paste0("interestingCondition", 1:3)
process_1_df(df, "id", condition)

id должен быть идентификатором - если data.frame взят из файла 'foo.txt', тогда используйте "foo.txt" для идентификатора.Исходный вопрос пытался представить данные из нескольких файлов в виде матрицы, но это предполагает, что в каждом файле выбрано одинаковое количество интересных строк.Здесь стратегия заключается в создании фрейма данных, который содержит файл, из которого получено интересующее условие, и значение интересующего условия.Этот фрейм данных полезен при обработке нескольких файлов ...

Это работает с образцом данных, установленным как:

> condition <- paste0("interestingCondition", 1:3)
> process_1_df(df, "id", condition)
       columnOfInterest id
1 interestingCondition2 id
2 interestingCondition2 id
3 interestingCondition3 id
4 interestingCondition1 id
5 interestingCondition3 id
6 interestingCondition1 id

Вы можете расширить это для обработки файла

process_1_file <- function(file_name, condition)
    read_csv(file_name) %>%                   # better: input only columnOfInterest
        process_1_df(file_name, condition)

Как предполагает @DJJ, реализация data.table process_1_file(), вероятно, будет очень компактной и эффективной - fread(file_name)[columnOfInterest %in% condition, columnOfInterest]

Для обработки нескольких файлов используйте пакет purr

library(purrr)
process_files <- function(file_names, condition)
    map(file_names, process_1_file, condition) %>%
        bind_rows()

dir(pattern="*.csv") %>% process_files(condition)

Конечным результатом является один фрейм данных со столбцом интересных условий и другим столбцом, указывающим, из какого файла журнала получено интересующее условие.Этот фрейм данных «длинного» формата теперь можно обрабатывать / суммировать по желанию.

0 голосов
/ 09 июня 2018

Кто-нибудь знает, почему это происходит?

Ваш цикл ... не работает.Причины немного сложны, но я сделал рабочий пример в базе R, используя простые циклы (без * применения функций), надеюсь, вы сможете следовать, и, надеюсь, это в достаточной степени представляет вашу проблему.

Научитесь ходить, прежде чем бежать.Изучите базовые циклы, прежде чем научиться делать это более кратко с apply(), lapply() и т. Д. Изучите стандартную оценку (то есть регулярное использование самого языка программирования R), прежде чем углубляться в нестандартную оценку (data.table, tidyverse, purrr и т. Д.)

Сначала мы создадим несколько фреймов данных и запишем их в файлы

owd <- getwd()
dir.create("sotest")
setwd("sotest")

set.seed(1)

flist <- c("dtf1.txt", "dtf2.txt", "dtf3.txt")

for (i in 1:length(flist)) {
    dtf <- data.frame(
      X=sample(1:10),
      coi=sample(c("ic1", "ic2", "ic3", "nic1"), 10, replace=TRUE)
    )
    write.table(dtf, flist[i], row.names=FALSE, sep="\t")
}

После запуска у вас должна быть папка с именем "sotest", содержащаятри разделенных табуляцией txt-файла.

Затем мы получим список доступных файлов и пройдем по нему.

flist <- list.files(pattern=".txt")
WrongResult <- list()
interesting <- c("ic1", "ic2", "ic3")

for (v in 1:length(flist)) {

    dtf <- read.delim(flist[v], header=TRUE, sep="\t", stringsAsFactors=FALSE)
    WrongResult[[v]] <- dtf[dtf$coi %in% interesting, "coi"]

}

WrongResult

setwd(owd)

Я сохраняю вывод в виде списка вместо матрицы, поскольку длина объекта, создаваемого в каждой итерации цикла, не одинакова.

0 голосов
/ 09 июня 2018

Я не помню, как это сделать с data.frame, поэтому я попробую с data.table.Возможно, вам придется установить пакет data.table, если у вас его нет install.packages("data.table")

library(data.table)
dt <- data.table(df)

Затем вы можете переписать свой код следующим образом

subset..table <- function(dt){
    dt[columnOfInterest %in% c("interestingCondition1",
                               "interestingCondition2",
                               "interestingCondition3"),columnOfInterest]
}


myfun <- function(x){
### DD
    ## x interp string representing  file name

### Purpose
    ## read and subset

    dt <- fread(x,header=TRUE,sep="\t")
    subset..table(dt)

}

res..list <- lapply(ListOfFiles, myfun)

Редактировать

, например, используя ваш пример.

df <- data.frame(
  X = sample(1:10),
  columnOfInterest= sample(c("interestingCondition1",
    "interestingCondition2", "interestingCondition3", 
    "NotinterestingCondition1"), 10, replace = TRUE))


dt <- data.table(df)
subset..table(dt)

даст

#[1] "interestingCondition2" "interestingCondition3" "interestingCondition1"
#[4] "interestingCondition2" "interestingCondition1" "interestingCondition2"
#[7] "interestingCondition3" "interestingCondition1" "interestingCondition3"

Если вы удовлетворены функцией subset..table,тогда вам просто нужно использовать функцию myfun, чтобы получить то, что вы хотите.Функция fread автоматически выдаст вам data.table.

...