根据列名正则表达式和元素值

时间:2018-03-18 17:59:27

标签: python r pandas matrix

这是一个试图过滤一个矩阵的问题。输入文件类型是.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-G1s2-G1代表来自 相同 组的不同样本,而s1-G1s3-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-G2G1中的G2 }),那些不包含在结果矩阵中;同样, OTU3 行也会因同一原因而被排除(它在两个组G2G3中包含多个非零值。

另一个矩阵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

感谢您的考虑和支持。我期待着你的回复。

德文

1 个答案:

答案 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过滤原始的宽数据表。