R-Объединение Нескольких Больших Фреймов Данных (Сортировка)



Я бы предпочел сделать следующее в R, но я открыт для (легко узнать) других решений.



У меня есть несколько (скажем, 99) файлов с разделителями табуляции (назовем их S1.txt через S99.txt) с таблицами, все с точно таким же форматом. Каждая таблица ~2,000,000 cols на 5 строк. Вот пример игрушки:



ID    Chr    Position    DP1    DP2
A1 1 123 1.5 2.0
A2 1 124 1.4 0.3


ID по определению уникален и всегда находится в одном и том же порядке, Chr и Pos всегда находятся в одном и том же порядке. Единственное, что отличается в каждом входном файле, - это столбец DP1 и DP2 колонка. Выходная таблица, которую я хотел бы "сверить", я думаю, это слово. Вот пример вывода, если бы было только 3 примера входных файлов.



ID    Chr    Position    S1.DP1  S1.DP2    S2.DP1    S2.DP2  S3.DP1  S3.DP2
A1 1 123 1.5 2.0 1.2 2.0 1.5 2.1
A2 1 124 1.4 0.3 1.0 0.5 0.5 0.05


Обратите внимание, что каждый входной файл содержит новый столбец, созданный для DP1 и DP2. Кроме того, имя столбцов информативно (говорит мне, из какого входного файла оно пришло и какая точка данных - DP).

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



Другим моим решением было инициализировать фрейм данных, а затем загрузить каждый файл и добавить точки данных, но это будет использовать цикл и будет невероятно медленным и ужасным.
Поэтому мне нужно более элегантное решение. Спасибо за вашу помощь.
605   3  

3 ответов:

Я перечитал ваш вопрос и придумал еще лучшее решение.

Во-первых, я бы не стал загружать все свои .txt файлы сразу в R. Если ваш .txt файлы 2e6x5 и есть 100 из них вы, вероятно, будет работать из оперативной памяти, прежде чем загрузить их все. Я бы загружал их по одному за раз и итеративно объединял их.

library(readr) #Use this to load your data, it is much better than the base functions

f <- list.files(path = "path/to/file", pattern = "*.txt", full.names = TRUE)

d <- read_delim(f[1], delim = "\t") 

idx = c("ID", "Chr", "Position")

for (i in seq(2, length(f)){

    d_temp <- read_delim(f[i], delim = "\t")

    d <- merge(d, d_temp, by = idx)

    rm(d_temp) #not necessary but I like to include to make explicit
}

Именование d

n <- expand.grid(paste0("S", seq(1, length(f)), c("DP1", "DP2"))
names(d)[!names(d) %in% idx] <- paste(n[ ,1], n[ ,2], sep = ".")

Обновить

Тьфу, я пропустил очевидное, если у вас действительно есть 100 2e6x5 .txt файлы, вы, вероятно, не собираетесь чтобы иметь возможность использовать R для этой задачи. Я сомневаюсь, что будет возможно хранить фрейм данных 2e6X500 в R. даже если вы на сервере с нагрузками ОЗУ время вычисления будет нетривиальным. Я думаю, что самый важный вопрос в будущем - что вы пытаетесь сделать с этими данными. Как только вы ответите на этот вопрос, вы сможете эффективно использовать свои данные.

Я предполагаю, что все файлы хранятся в одной папке и что вы хотите загрузить все файлы с расширениями .txt в эту папку.

## List all the files in the current directory that end in .txt
files <- list.files(path = ".", pattern = "*.txt")

## Load them into a list called datlist and name each element after the file it came from
datlist <- lapply(files, read.table, sep = "\t")
names(datlist) <- gsub("(*).txt", "\\1", files)
Однако для целей воспроизводимого примера я собираюсь вручную создать список фреймов данных, подобный тому, который вы показали.
S1 <- read.table(text = "ID    Chr    Position    DP1    DP2
A1    1       123        1.5    2.0
A2    1       124        1.4    0.3", header = TRUE)

S2 <- read.table(text = "ID    Chr    Position    DP1    DP2
A1    1       123        1.2    2.0
A2    1       124        1.0    0.5", header = TRUE)

S3 <- read.table(text = "ID    Chr    Position    DP1    DP2
A1    1       123        1.5    2.1
A2    1       124        0.5    0.05", header = TRUE)

datlist <- list(S1 = S1, S2 = S2, S3 = S3)

Теперь загрузите пакеты, которые мы собираемся использовать

library("dplyr")
library("tidyr")

С помощью комбинации функций dplyr и tidyr мы можем получить желаемый результат:

## First, combine the list into a single data frame, adding a column to indicate
## which file each row came from
bind_rows(datlist, .id = "file") %>%
  ## Gather this into a longer format with DP1/DP2 as variables
  gather(key = col, value = value, which(!names(.) %in% c("ID", "Chr", "Position", "file"))) %>%
  ## Create a new column that combines the file name and DP1/DP2 -- this will be
  ## the final column names
  unite(newcol, file, col, sep = ".") %>%
  ## Spread the data so that each combination of file and DP1/DP2 is its own
  ## column
  spread(newcol, value)

Конечный результат:

## Source: local data frame [2 x 9]

##       ID   Chr Position S1.DP1 S1.DP2 S2.DP1 S2.DP2 S3.DP1 S3.DP2
##   (fctr) (int)    (int)  (dbl)  (dbl)  (dbl)  (dbl)  (dbl)  (dbl)
## 1     A1     1      123    1.5    2.0    1.2    2.0    1.5   2.10
## 2     A2     1      124    1.4    0.3    1.0    0.5    0.5   0.05

Один вкладыш с основанием R

l = list(S1=S1, S2=S2, S3=S3)

idx = c("ID","Chr","Position")

d <- Reduce(function(x, y) merge(x, y, by = idx), l)

Обновить

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

 n <- expand.grid(names(l), setdiff(names(S1), idx))
 names(d)[!names(d)%in%idx] <- paste(n[ ,1], n[ ,2], sep = ".")

Comments

    Ничего не найдено.