如何输出列表中的指定列?

最新更新:
最简单的方法还是R 一句话d <-data1[,data2$Header] (data1就是这里的1.txt, data2就是2.txt)

今天遇到了一个小问题,想把转录组read count矩阵中指定样品(指定列)的表达量挑选出来,总共从500多个样中选200个,数据量在500Mb左右。为了简化问题,我先测试了一下。
假设有1.txt和2.txt两个文件,格式如下:

$ more 1.txt
1       2       3       4       5       6
a       b       c       d       e       f
g       h       i       j       k       l
$ more 2.txt
1
2

现在根据2.txt里指定列的信息从1.txt里挑第一列和第二列出来,最终想得到这样的结果:

1   2
a   b
g   h

方案1. shell脚本(冗杂且提取失败)

我写了一个简易的shell脚本可惜不成功

$ more test.sh
a=`awk '{print NF}' 1.txt`  #统计1.txt的列数
b=`wc -l |2.txt`   #统计2.txt的行数
for (( i=1;i<=$a;i++))
do
for(( j=1;j<=$b;j++ ))
do
h=`cat 1.txt |awk 'NR==1{print}'|awk '{print '$i'}'` #逐个读取1.txt第一列
k=`cat 2.txt |awk 'NR=='$j'{print}'` #读取2.txt的每一行
     if [[ h -eq k ]];
    # then echo $k
     then echo `cat 1.txt |awk '{print '$i'}'`  
fi
done
$ sh test.sh 
1 1 
2 2 

echo结果不太对,提取列之后要paste 还是不方便组合

琢磨了一阵后,我向生信技能树的小伙伴们求助,果然群体的智慧是无穷的~

方案2. awk提取(感谢王诗翔的建议和帮助)

原话:

linux处理文本的核心是以行为基础,我的意思是利用现有的脚本将列变成行,然后使用join拼接 awk '{for(i=0;++i<=NF;)a[i]=a[i]?a[i] FSi:i}END{for(i=0;i++<NF;)print a[i]}' 1.txt | join - 2.txt | awk '{for(i=0;++i<=NF;)a[i]=a[i]?a[i] FSi:$i}END{for(i=0;i++<NF;)print a[i]}' 行列转换的命令网上就有,也可以自己写

$ awk '{for(i=0;++i<=NF;)a[i]=a[i]?a[i] FS $i:$i}END{for(i=0;i++<NF;)print a[i]}'  1.txt | join - 2.txt |  awk '{for(i=0;++i<=NF;)a[i]=a[i]?a[i] FS $i:$i}END{for(i=0;i++<NF;)print a[i]}' 
1 2
a b
g h

拆解一下 先把行和列置换,然后再用join命令按行匹配,再置换一次就好了

$ awk '{for(i=0;++i<=NF;)a[i]=a[i]?a[i] FS $i:$i}END{for(i=0;i++<NF;)print a[i]}'  1.txt >01
1 a g
2 b h
3 c i
4 d j
5 e k
6 f l
$ join 01 2.txt >02
1 a g
2 b h
$ awk '{for(i=0;++i<=NF;)a[i]=a[i]?a[i] FS $i:$i}END{for(i=0;i++<NF;)print a[i]}' 02
1 2
a b
g h

不得不说学好这里shell命令真的方便,join实现的功能之前我是用python脚本弄的......

不过,这里有个问题需要注意,join是按行提取的,如果有一行在1.txt和2.txt里面不匹配,就会停止检索。
比如,2.txt里面多加一行9(1.txt里面没有)

$ more 2.txt
1
2
9
3
$join 1.txt 2.txt
1 a g
2 b h

后面的第3行3 c i就没有被提取出来

方案3. R包dplyr select()提取(感谢严涛的建议和帮助,这是他的个人R学习笔记里的一部分)

首先在2.txt首行加个Header 方便提取

$ more 2.txt
Header
1
2
$ R
>library(dplyr)
>3.txt <- 1.txt %>% select(one_of(dput(as.character(2.txt$Header))))

这里%>% 是管道函数,把左边文件的值发送给右边文件,并作为右边文件件表达式的第一个参数, select()允许我们快速通过变量名对数据集取子集,后面的看的不是很懂
推荐一篇王诗翔写的介绍dplyr的博客详细了解一下
使用dplyr进行数据转换

方案4.python按行提取(我之前用的脚本)

还是要先转置,然后再提,不过只提了前两列

#!/usr/bin/python
file1=open("",'r')
file2=open("1.txt",'r')
file3=open"2.txt",'w')
file1_dict={}
while 1:
    line1=file1.readline()
    if not line1:
        break
    lin=line1.strip('\n')
    lin1=lin.split('\t')
    file1_dict[lin1[0]]=lin1[1]
while 1:
    line2=file2.readline()
    if not line2:
        break
    line=line2.strip('\n')
    if line in file1_dict:
        value=file1_dict[line]
        file3.write(line+'\t'+value+'\n')
file1.close()
file2.close()
file3.close()

方案5. perl脚本提取(感谢刘帅的建议和帮助)

perl脚本处理的思路有很多,这里是用先转置成行再存数组匹配,大致是这样
转置

while (my $tem=<IN>){
      chomp $tem;
   my @ll=split /\t/,$tem;
   push @sample,$ll[0];
      for my $i (1..$#ll){
       push @{$snp{$snp_name[$i]}},$ll[$i];
   }
}

提取行

while (<IN1>) {
        chomp;
        my @a=split/\s+/,$_;
        push @sample,$a[0];

}
while (<IN2>) {
        chomp;
        my @b=split/\s+/,$_;
foreach $i(@sample) {
        if ($i eq $b[0]) {
                print OUT "$_\n";
        }

完整版看这里:
Trans.pl

my @id;
my @chr;
my @pos;
my $head1=<IN>;
chomp $head1;
my @snp_name=split /\t/,$head1;


while (my $tem=<IN>){
      chomp $tem;
   my @ll=split /\t/,$tem;
   push @sample,$ll[0];
      for my $i (0..$#ll){
       push @{$snp{$snp_name[$i]}},$ll[$i];
   }
}

open (OUT,">$outfile") || die "Can't creat $outfile, $!\n" ;;
    for my $i (0..$#snp_name) {
        my $content=join("\t",@{$snp{$snp_name[$i]}});
        print OUT "$snp_name[$i]\t",$content,"\n";
    }


sub USAGE {#
    my $usage=<<"USAGE";
ProgramName: Transpose of Matrix
Version:    $version
Contact:    Shuai Liu <ls2106\@msstate.edu>; 
Program Date:   2018.6.9
Usage:
    Options:
    -infile     <file>  input file,forced
    -outfile    <file>  output file,forced
    -h          Help

USAGE
    print $usage;
    exit;
}

Extract.pl

#!/usr/bin/perl -w
use strict;
use warnings;
use Getopt::Long;
my $version="1.0";
#######################################################################################
my ($list,$infile,$outfile);
GetOptions(
                "help|?" =>\&USAGE,
                "list:s"=>\$list,
                "infile:s"=>\$infile,
                "outfile:s"=>\$outfile,
                                ) or &USAGE;
&USAGE unless ($list||$infile||$outfile);
#########################  vcffilter &  vcf imputation     ###############################
open (IN1, "<$list") || die "Can't creat $list, $!\n" ;
my @sample;
my $a;
my $i;
my @b;
my @a;
while (<IN1>) {
    chomp;
    my @a=split/\s+/,$_;
    push @sample,$a[0];
}
open (IN2, "<$infile") || die "Can't creat $list, $!\n" ;
open (OUT, ">$outfile") || die "Can't creat $list, $!\n" ;

while (<IN2>) {
    chomp;
    my @b=split/\s+/,$_;
foreach $i(@sample) {
    if ($i eq $b[0]) {
        print OUT "$_\n";
    }
}
}
sub USAGE {#
    my $usage=<<"USAGE";
ProgramName: Extract rows from list
Version:    $version
Contact:    Shuai Liu <ls2106\@msstate.edu>; 
Program Date:   2018.6.9
Usage:
    Options:
    -list       <file>  list file,forced
    -infile     <file>  input file,forced
    -outfile    <file>  output file,forced
    -h          Help
USAGE
    print $usage;
    exit;
}

方案6. plink提取(样品很多的终极选择)

plink --vcf input.vcf --noweb --keep-fam id.txt --recode --make-be
d --out output

id.txt里面按行写入要提取的列名就行,很方便

网盘下载链接 链接:
Extract.pl
https://pan.baidu.com/s/1pCdM0tch8Jl2QeZO4clQ9g 密码:97hy

Trans.pl
https://pan.baidu.com/s/18aMepxBrk7EHbAXmTfVyOw 密码:b10o

非常感谢给予帮助的小伙伴,当然还有很多方法可以实现。P.S.最初的简陋版shell如果有高手看出问题,欢迎留言给我~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容

  • 转载 原文的排版和内容都更加友好,并且详细,我只是在这里贴出了一部分留作自己以后参考和学习,如希望更详细了解AWK...
    XKirk阅读 3,218评论 2 25
  • 应不应该,合不合适,可不可以……
    沉淀AQ阅读 159评论 0 0
  • 看着干净明朗的宿舍,心情也一下子明朗了起来。 有时候你真的不会知道只是简单地拾掇房间这样的小事也会改变你的心情。 ...
    春无忧阅读 1,508评论 6 3
  • 01 话接上回,从老家来上海投奔姑父以后,我立即就开始寻思找工作的事情。 姑父客气的说道:“不急不急,先休息个几天...
    西门吹饼阅读 219评论 2 2