这是一个试图过滤一个矩阵的问题。输入文件类型是.txt文件,其包含作为列的样本名称,作为行/索引的唯一(序列)标识符,并且矩阵的元素是针对给定样本观察到的序列的计数。如果你熟悉扩增子测序(16-S微生物组,ITS真菌/植物等),是的,这是一张OTU表,但是如果你没有,那就无所谓了,我发誓!请注意我可以控制输入文件列的名称,因此如果您认为合适,可以随意建议更好的命名约定。我之所以指出这一点,只是因为我理解像Pandas这样的软件包有能力保留多级命名约定;请记住输入文件只是一个文本文件,所以我只能重命名'我的带有分隔符的输入文件应该在下游过滤中证明是有用的。
我已经在R和Python中创建了一个示例数据集,因此可以随意使用这两个数据集进行重新创建。不同意命名R和Python文件的道歉,但我想让答案更容易区分你是采用Python还是R方法。
## Python enthusiasts:
import pandas as pd
df = pd.DataFrame(
[[1,2,0,0,0,0], [3,0,4,0,0,0], [0,0,5,6,7,0], [0,0,8,0,0,0], [0,0,0,0,0,99]],
columns=['s1-G1', 's2-G1', 's3-G2', 's4-G2', 's5-G3', 's6-G3'],
index=['OTU1', 'OTU2', 'OTU3', 'OTU4', 'OTU5'])
## R enthusiasts:
ra <- c(1,2,0,0,0,0)
rb <- c(3,0,4,0,0,0)
rc <- c(0,0,5,6,7,0)
rd <- c(0,0,8,0,0,0)
re <- c(0,0,0,0,0,99)
mat <- rbind(ra,rb,rc,rd,re)
colnames(mat) <- c("s1-G1", "s2-G1", "s3-G2", "s4-G2", "s5-G3", "s6-G3")
rownames(mat) <- c("OTU1", "OTU2", "OTU3", "OTU4", "OTU5")
希望你得到一个如下所示的数据集:
s1-G1 s2-G1 s3-G2 s4-G2 s5-G3 s6-G3
OTU1 1 2 0 0 0 0
OTU2 3 0 4 0 0 0
OTU3 0 0 5 6 7 0
OTU4 0 0 8 0 0 0
OTU5 0 0 0 0 0 99
正如您可能已经猜到的那样,列名实际上指定了两个级别或组织,尽管它们连在一起:样本名称和组名称。因此,s1-G1
,s2-G1
代表来自 相同 组的不同样本,而s1-G1
和s3-G2
代表不同的样本来自 不同的 组。我指出这一点是因为过滤目标需要某种表达方式按名称的G#
部分进行分组,而S#
部分与此问题无关。
好吧,那么目标是什么?目标是过滤此数据集,以便将此矩阵拆分为两个新的基质:一个称为df_uniq
,另一个称为df_dupd
。每个新矩阵的细节:
我想过滤行,这样当我们观察到任何数字列的值大于零的一个或多个矩阵元素时,df_uniq
矩阵中的任何行都包含在内.EXCEPT所有这些匹配仅包含在一个唯一 G
值中。在上面的示例矩阵中,这将产生一个新的df_uniq
矩阵,如下所示:
s1-G1 s2-G1 s3-G2 s4-G2 s5-G3 s6-G3
OTU1 1 2 0 0 0 0
OTU4 0 0 8 0 0 0
OTU5 0 0 0 0 0 99
因为我们在s1-G1
列中观察到大于零的值,而对于行 OTU2 (它们分为两个独立的组s3-G2
和G1
中的G2
}),那些不包含在结果矩阵中;同样, OTU3 行也会因同一原因而被排除(它在两个组G2
和G3
中包含多个非零值。
另一个矩阵df_dupd
将包含与df_uniq
中的内容相反的任何行 - 矩阵中至少有一个非零元素存在* *观察到至少两个独特的G
样本。初始矩阵中的值将生成一个新表,其中包含我们在df_uniq
表中未包含的内容:
s1-G1 s2-G1 s3-G2 s4-G2 s5-G3 s6-G3
OTU2 3 0 4 0 0 0
OTU3 0 0 5 6 7 0
感谢您的考虑和支持。我期待着你的回复。
德文
答案 0 :(得分:1)
以下使用data.table的示例应该让您入门:
library(data.table)
ra <- c(1,2,0,0,0,0)
rb <- c(3,0,4,0,0,0)
rc <- c(0,0,5,6,7,0)
rd <- c(0,0,8,0,0,0)
re <- c(0,0,0,0,0,99)
mat <- rbind(ra,rb,rc,rd,re)
colnames(mat) <- c("s1-G1", "s2-G1", "s3-G2", "s4-G2", "s5-G3", "s6-G3")
rownames(mat) <- c("OTU1", "OTU2", "OTU3", "OTU4", "OTU5")
# Convert to data.table
dat.wide <- data.table(mat)
# add back in OTU as column
dat.wide[, OTU := c("OTU1", "OTU2", "OTU3", "OTU4", "OTU5")]
# Convert to long format
dat.long <- melt(dat.wide)
# split sample and group name into separate columns, creating new column "value"
dat.long[, c("sample","group") := tstrsplit(variable, split="-")]
# remove original joint sample-group column
dat.long[, variable := NULL]
# get unique OTUs
unique.OTUs <- dat.long[, list(N=sum(value)), by=list(group, OTU)][, list(Ngroups=sum(N>0)), by=OTU][Ngroups==1]$OTU
dat.wide[OTU %in% unique.OTUs]
# output:
# s1-G1 s2-G1 s3-G2 s4-G2 s5-G3 s6-G3 OTU
# 1 2 0 0 0 0 OTU1
# 0 0 8 0 0 0 OTU4
# 0 0 0 0 0 99 OTU5
dat.wide[! (OTU %in% unique.OTUs)]
# output:
# s1-G1 s2-G1 s3-G2 s4-G2 s5-G3 s6-G3 OTU
# 3 0 4 0 0 0 OTU2
# 0 0 5 6 7 0 OTU3
更详细:长格式表看起来像
OTU value sample group
OTU1 1 s1 G1
OTU2 3 s1 G1
OTU3 0 s1 G1
OTU4 0 s1 G1
OTU5 0 s1 G1
OTU1 2 s2 G1
OTU2 0 s2 G1
OTU3 0 s2 G1
OTU4 0 s2 G1
OTU5 0 s2 G1
OTU1 0 s3 G2
OTU2 4 s3 G2
OTU3 5 s3 G2
OTU4 8 s3 G2
OTU5 0 s3 G2
OTU1 0 s4 G2
OTU2 0 s4 G2
OTU3 6 s4 G2
OTU4 0 s4 G2
OTU5 0 s4 G2
OTU1 0 s5 G3
OTU2 0 s5 G3
OTU3 7 s5 G3
OTU4 0 s5 G3
OTU5 0 s5 G3
OTU1 0 s6 G3
OTU2 0 s6 G3
OTU3 0 s6 G3
OTU4 0 s6 G3
OTU5 99 s6 G3
这使我们能够首先对每组/ OTU组合的观察结果进行求和:
step1 <- dat.long[, list(N=sum(value)), by=list(group, OTU)]
给我们
group OTU N
G1 OTU1 3
G1 OTU2 3
G1 OTU3 0
G1 OTU4 0
G1 OTU5 0
G2 OTU1 0
G2 OTU2 4
G2 OTU3 11
G2 OTU4 8
G2 OTU5 0
G3 OTU1 0
G3 OTU2 0
G3 OTU3 7
G3 OTU4 0
G3 OTU5 99
链上[,列表(Ngroups = sum(N> 0)),by = OTU]来计算非零观测值的组数
step2 <- step1[, list(Ngroups=sum(N>0)), by=OTU]
给我们
OTU Ngroups
OTU1 1
OTU2 2
OTU3 2
OTU4 1
OTU5 1
最后在[Ngroups == 1]上链接以选择仅在组上发生非零观测的行
step3 <- step2[Ngroups==1]
step3
给我们
OTU Ngroups
OTU1 1
OTU4 1
OTU5 1
最后,根据我们上面所做的独特OTU过滤原始的宽数据表。