R - 合并多个大型数据帧(整理)

时间:2015-12-15 23:05:30

标签: r merge

我更喜欢在R中执行以下操作,但我愿意(易于学习)其他解决方案。

我有多个(比方说99个)制表符分隔的文件(让我们通过S99.txt称它们为S1.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个Sample输入文件,那么这是一个输出示例。

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: merging a lot of data.frames 我也知道合并,虽然我觉得你最终得到了奇怪的列名: How to join (merge) data frames (inner, outer, left, right)?

我的另一个解决方案是初始化一个数据帧,然后加载每个文件并添加数据点,但这将使用一个循环,并且非常慢和可怕。 所以,我需要一个更优雅的解决方案。谢谢你的帮助。

3 个答案:

答案 0 :(得分:2)

我将假设所有文件都存储在一个文件夹中,并且您要加载该文件夹中包含## 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")

现在加载我们将要使用的软件包

## 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)

通过混合使用dplyr和tidyr函数,我们可以得到您想要的结果:

## 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

最终结果:

<?php

require_once realpath(dirname(__FILE__).'/google-api-php-client/autoload.php');

$client_email = '1234567890-a1b2c3d4e5f6g7h8i@developer.gserviceaccount.com';
$private_key = file_get_contents('MyProject.p12');
$scopes = array('https://www.googleapis.com/auth/sqlservice.admin');
$credentials = new Google_Auth_AssertionCredentials(
    $client_email,
    $scopes,
    $private_key
);

$client = new Google_Client();
$client->setAssertionCredentials($credentials);
if ($client->getAuth()->isAccessTokenExpired()) {
  $client->getAuth()->refreshTokenWithAssertion();
}

$sqladmin = new Google_Service_SQLAdmin($client);
$response = $sqladmin->instances
    ->listInstances('examinable-example-123')->getItems();
echo json_encode($response) . "\n";

答案 1 :(得分:2)

我重新阅读了你的问题并想到了一个更好的解决方案。

首先,我不会立即将所有.txt文件加载到R中。如果您的.txt文件是2e6x5并且有100个文件,则在加载它们之前可能会耗尽RAM。我会一次加载一个并迭代合并它们。

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来执行此任务。我怀疑是否有可能在R中存储一个2e6X500数据帧。即使你在服务器上有大量的RAM计算时间也是非常重要的。我认为最重要的问题是你要对这些数据做些什么。一旦你回答这个问题,你就可以有效地使用你的数据。

答案 2 :(得分: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)

<强>更新

忘记变量名称。这可能有点过分,但这是我能想到的最好的方法,以避免对名称进行硬编码。

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