2015-12-15 4 views
2

Я бы предпочел сделать следующее в R, но открыт для (легко учиться) другим решениям.R - Объединение нескольких больших Dataframes (Collating)

У меня есть несколько (скажем 99) файлов с разделителями-табуляторами (давайте назовем их S1.txt через S99.txt) с таблицами, все с одинаковым форматом. Каждая таблица составляет ~ 2 000 000 колос на 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. ТАКЖЕ, имя столбцов является информативным (сообщает мне, какой файл ввода он пришел от &, который datapoint-DP).

Я нашел вопросы, когда столбцы различны: R: merging a lot of data.frames Я также знаю о слиянии, хотя я чувствую, что вы в конечном итоге со странными названиями колонок: How to join (merge) data frames (inner, outer, left, right)?

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

ответ

2

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

Прежде всего, я не буду загружать все .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 = ".") 

Update

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

+0

Я получаю все образцы в один файл, чтобы отформатировать их для программы. Он требует, чтобы файлы были в том формате, который у меня был. Я беспокоился, что это слишком много для R, но не знаю другого способа сделать это. У меня была восходящая программа, создающая файл для образца, но теперь нужно собрать все вместе для последующей программы. –

+0

Есть ли другой вариант для этого, относительно простой? Я не против изучать новые вещи, но также нужно сделать это для проекта. Благодарю. –

+1

@GaiusAugustus Первое, что я хотел бы сделать, это попробовать один из предложенных подходов и посмотреть, работает ли он. Однако Unix будет вашим самым быстрым вариантом. Для этого используйте команду 'cut' для удаления уникальных идентификаторов (т. Е. ID, Chr, Position) из S2.txt в S99.txt. Затем «вставляйте» S1.txt через S99.txt. Unix будет не только быстрее, но и никогда не связан с памятью. –

2

Я собираюсь предположить, что все файлы хранятся в одной папке и что вы хотите загрузить все файлы с расширениями .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 
1

Один лайнер с основанием 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) 

Update

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

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

Зачем давать два отдельных ответа? Лучше включить их в один imo – Jaap

Смежные вопросы