注册 登录
编程论坛 C++教室

利用c++分析生物信息学数据疑问

cpp_初学者 发布于 2011-06-30 10:42, 1805 次点击
各位网友,想请问是否有任何关于如何利用c++进行生物信息学分析的书刊或工具或网站,可以介绍吗?
我之前有学过perl和awk...
现在想试着学习利用c++,来进行数据分析...
多谢各位网友的分享和指导
我主要感兴趣的是如何利用c++来读取一个挡案内的数据后,并加以分析和处理...
36 回复
#2
lz10919149992011-06-30 13:16
不懂啊,我想你在这个网站里应该能找到你想要的书:http://www.
#3
cpp_初学者2011-06-30 15:58
回复 2楼 lz1091914999
谢谢你的分享 :)
请问你对c++或生物信息学,都很了解的?
#4
lz10919149992011-06-30 18:53
回复 3楼 cpp_初学者
呵呵,C++略懂,生物学不懂。。。
#5
pangding2011-06-30 19:35
生物信息学分析……
估计几乎不会有书吧 c++ 和这个合在一起讲吧……
你用 perl 解决不了类似的问题,那我觉得 c++ 也会很困难。
因为解析字符串或者匹配正则表达式之类的要利用第三方库才可以,而且,你会觉得即使用库也异常的费劲。perl 里几行的代码跑到 c++ 里等价的代码要十几行,几十行都很正常。

如果你以前只学过 perl 和 awk 的话,那么 c++ 和这两种语言的区别还是很大的。也许在学的过程中阻力会比较大,要作好心理准备哦~
#6
pangding2011-06-30 19:39
如果数据量很大的话,考虑用 sql 之类的是正确的。或者找专门用来统计分析的工具也行,比如 sas, spss 之类的。专门的数学软件也可能会更好用,比如 matlab, mathematics 之类的。

当然我说的这些意见可能没什么参考价值,因为我也不懂生物信息是分析什么的。


[ 本帖最后由 pangding 于 2011-6-30 19:40 编辑 ]
#7
cpp_初学者2011-07-01 11:06
回复 4楼 lz1091914999
呵呵,那我们互相交流下,好吗? :)
以下是一些生物信息学,常见的数据格式:
程序代码:

目的: 读取input_file内的数据后,计算共有多少个A,C,G,T(">"的内容,无需计算)
input_file
>header_1
ACGTGAGAGATAGAGC
>header_2
AGATGAGATGAGAGATAGA

理想结果:

35

我使用awk的方法:

awk '$0!~">"{total += length($1)}END{print total}' input_file
35

若是利用c++,你能分享如何读取及计算出input_file内,共有多少个A,C,G,T,etc
#8
cpp_初学者2011-07-01 11:09
回复 5楼 pangding
pangding,你好 :)
请问你对c++,是否有研究呢?
以下是一些生物信息学,常见的数据格式:
程序代码:

目的: 读取input_file内的数据后,计算共有多少个A,C,G,T(">"的内容,无需计算)
[home@cpp]cat input_file.txt
>header_1
ACGTGAGAGATAGAGC
>header_2
AGATGAGATGAGAGATAGA

理想结果:

35

我使用awk的方法:
程序代码:

[home@cpp]awk '$0!~">"{total += length($1)}END{print total}' input_file.txt > output_file.txt
[home@cpp]cat output_file.txt
35

若是利用c++,你能分享如何读取及计算出input_file内,共有多少个A,C,G,T,etc
#9
cpp_初学者2011-07-01 11:10
回复 5楼 pangding
pangding,你好 :)
请问你对c++,是否有研究呢?
以下是一些生物信息学,常见的数据格式:
程序代码:

目的: 读取input_file内的数据后,计算共有多少个A,C,G,T(">"的内容,无需计算)
[home@cpp]cat input_file.txt
>header_1
ACGTGAGAGATAGAGC
>header_2
AGATGAGATGAGAGATAGA

理想结果:

35

我使用awk的方法:
程序代码:

[home@cpp]awk '$0!~">"{total += length($1)}END{print total}' input_file.txt > output_file.txt
[home@cpp]cat output_file.txt
35

若是利用c++,你能分享如何读取及计算出input_file内,共有多少个A,C,G,T,etc
#10
cpp_初学者2011-07-01 12:00
回复 6楼 pangding
awk和perl是很容易写出其程序...
但若是挡案太大时,就需要很长的时间...
因此,我才想看,是否能用c++,加快分析的速度...
希望你对c++的了解,能互相学习 :)
真的很谢谢你的帮忙...
#11
pangding2011-07-01 16:05
根据你的程序,是不是就是要一个这样的功能:
> 开头的行略去。
不是的行一肯只含有 agtc 这四个字母,数一数就行了?

这个东西能慢到哪去呀。你上传个数据实例我测测呗。

[ 本帖最后由 pangding 于 2011-7-1 16:40 编辑 ]
#12
cpp_初学者2011-07-01 17:20
回复 11楼 pangding
你好,版主...
以下是我要读取的输入挡案内容:
程序代码:

[home@cpp]cat input_file.txt
>header_1
ACGTGAGAGATAGAGC
>header_2
AGATGAGATGAGAGATAGA
.
.

写出的c++程序,必须符合一下的条件:
1.若是开头是">",可以直接跳过,无需计算;
2.只计算不是">"的内容.并计算出其总额;
3.将从输入挡案读取及经c++程序处理后的计算结果,存入另一个挡案;
以下是我利用awk语言,所写出的程序内容:
程序代码:

[home@cpp]awk '$0!~">"{total += length($1)}END{print total}' input_file.txt > output_file.txt
[home@cpp]cat output_file.txt
35

#13
cpp_初学者2011-07-01 17:27
以下是我要读取的输入挡案内容(挡案内容,可能会大过1GB):
程序代码:

[home@cpp]cat input_file.txt
>header_1
ACGTGAGAGATAGAGC
>header_2
AGATGAGATGAGAGATAGA
.
.


写出的c++程序,必须符合一下的条件:
1.若是开头是">",可以直接跳过,无需计算;
2.只计算不是">"的内容.并计算出其总额;
3.将从输入挡案读取及经c++程序处理后的计算结果,存入另一个挡案;
以下是我利用awk语言,所写出的程序内容:
程序代码:

[home@cpp]awk '$0!~">"{total += length($1)}END{print total}' input_file.txt > output_file.txt
[home@cpp]cat output_file.txt
35

希望各位c++的高手,可以分享如何利用c++,写出一个类型awk语言的程序...
我利用的awk语言,在读取太大的挡案时,可能会需要很长的时间 :(
因此希望各位高手的c++程序,可以加快挡案的分析速度
谢谢 :)
#14
玩出来的代码2011-07-01 20:39
LZ先说清问题嘛,是不是每行只有agtc这几个字母?
说下你处理的文件大小,耗费的时间。不同的机器上不同的数据也不好说明问题。如果不仅限于C++的特性,对于几G的文件可以试试文件内存映射。
#15
cpp_初学者2011-07-01 21:49
回复 14楼 玩出来的代码
你好,每行多数的可能会是A,C,G,T,N,etc...
我主要的目的,是希望利用c++来计算,除了开头有">"行的内容...
其他行,总共有多少个英文字母的总合...
eg.
程序代码:

>header_1
ACGTGAGAGATAGAGC
>header_2
AGATGAGATGAGAGATAGA

以上的例子,header_1下面的行列,共有16个字母;header_2下面的行列,共有19个字母;
因此,我希望得到的理想结果是16+19= 35...

35

希望我的解释,有让你更了解的 :)
先多谢你的指导噢...
#16
pangding2011-07-01 22:49
一个多G的文件!那慢点也很正常的,你用 awk 写的要耗多少时间?
#17
pangding2011-07-01 23:25
我写了一个 sed 的,自己试了试能比 awk 的快3-5倍。
$ ls -lh in.txt
-rw-r--r-- 1 pd pd 31M 2011-07-01 23:20 in.txt
$ time awk '$0!~">"{total += length($1)}END{print total}' in.txt
28800000

real    0m7.436s
user    0m5.848s
sys     0m0.136s
$ time a=$(sed -e '/>/d' < in.txt | wc -lm); a+="r-p"; dc <<< $a

real    0m2.452s
user    0m1.936s
sys     0m0.112s
28800000
$
感觉用纯 C 也就最多再快一倍。


[ 本帖最后由 pangding 于 2011-7-1 23:28 编辑 ]
#18
玩出来的代码2011-07-01 23:56
pangding用的多大的文件测试?
#19
pangding2011-07-02 00:13
31M。不是 ls 了吗~
2880W个字符统计出来花个1秒钟我觉得也正常,这个东西线性的,没什么好算法。1G 的文件我这种老爷机估计都开不开……


[ 本帖最后由 pangding 于 2011-7-2 00:18 编辑 ]
#20
pangding2011-07-02 00:21
我用 c 语言写了一个,是 0.856s。看来还是比我估计的快了一些

把文件搞大了一倍,再跑就是 1.696s 秒。严格的正比关系~


[ 本帖最后由 pangding 于 2011-7-2 00:26 编辑 ]
#21
cpp_初学者2011-07-02 07:11
回复 20楼 pangding
谢谢你,pangding版主:)
可以请教你,若是用c++语言,应该如何写此程序呢?
我试着把档案该小过1GB,再做比较...
有些简单的计算,awk或许会蛮快...
但若是复杂些的计算,可能就要比较耗时 :(
我准备多些档案后,迟点再上载来,供大家讨论和分享 :)
#22
cpp_初学者2011-07-02 07:32
我主要遇到的问题,是不知该如何运用c++,来读取及分析一个档案的内容...分析后,又该如何将其储存于另一个档案 :(
用awk/sed/perl最方便的地方,或许是只需要在工作业面,输入要读取档案的名称后,利用“〉”符合,将分析结果,储存于另一个新档案...
我理想利用c++语言写好程序后的处理格式是:
程序代码:

c++程序名称 读取档案名称 结果档案名称
eg.
a.out input_file.txt output_file.txt
#23
cpp_初学者2011-07-02 07:42
若是以我提出的例子,c++的程序比awk/sed/perl慢些也没关系...
我主要是希望可以透过此例子,慢慢熟悉如何利用c++来写程序,分析数据...
谢谢...
请多指教 :)
#24
玩出来的代码2011-07-02 11:01
要求速度的话确实是c比较快,测试31M+的文件时间0.766秒左右,计算个数20808964,62M+的文件时间1.65左右。不过对于大文件的话,时间会大于线性了,文件小,我是一次读入内存的。
#25
cpp_初学者2011-07-02 11:37
回复 24楼 玩出来的代码
你好,请问可以分享你的c++程序吗?
希望可以更熟悉c++程序,是如何处理我的案例,谢谢噢 :)
#26
玩出来的代码2011-07-02 16:34
测试文件581M,计算个数350000000。
用C写耗时8.9秒左右。内存映射文件耗时15秒左右。
用C++单存的按行读取耗时172秒。,这个也很夸张,要保证将一行的数据读完,我使用了string,而他可能会导致内存的频繁分配释放,速度肯定慢。若按照固定大小来读取那么数据处理方法与C的就一样了,差别在于I/O处理速度上。这个就没有测试了。LZ确定要用C++来处理、
你说下用你的方法处理的耗时看看。。
#27
cpp_初学者2011-07-02 17:01
回复 26楼 玩出来的代码
你好,这是我使用的c++程序内容:
程序代码:

// aa.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[])
{
FILE *pOpen;
char chBuf[200];
int nSum=0;
long nLen=0;
int k;
pOpen = fopen("d:\\aa.txt","r"); //打开文件

if (pOpen==NULL)
{
printf("打开文件失败");
}
else
{
//打开文件成功,读取内容
fread(chBuf,200,1,pOpen);
//开始统计
nLen = strlen(chBuf);
for(int k=0;k < nLen;k++)
{
if(chBuf[k]=='A' || chBuf[k]=='C' || chBuf[k]=='G' || chBuf[k]=='T' || chBuf[k]=='N')
{
nSum++;
}
}
fclose(pOpen);
}

printf("%d\n",nSum);

return 0;
}

以上的程序,处理小档案,没有很大问题...
但还是有些不足的地方:
1.档案的名称,必须在c++程序内列明(如:aa.txt);
2.无法把结果,显示在新的档案内;

我理想的c++程序,是希望能按照一下的格式:
程序代码:

c++程序名称 读取档案名称 结果档案名称
eg.
a.out input_file.txt output_file.txt
a.out input_file2.txt output_file2.txt

非常感谢您的意见及改写以上的c++程序 :)
#28
玩出来的代码2011-07-02 17:47
额,你这是C程序啊,不是C++。并且你这个貌似与你说的要求不一样吧,
程序代码:

int main(int argc,char **argv)
{
    FILE *pf=fopen(argv[1],"rb+");
    fseek(pf,0,SEEK_END);
    int filesize=ftell(pf);
    fseek(pf,0,SEEK_SET);

    int num=1024*1024;
    char *pbFile=new char[num+1];
    bool bFlag=false;
    int target[26]={0};
    if(pbFile==NULL)
    {
        printf("new error");
        return -1;
    }
    while(filesize>0)
    {
        if(filesize<num)
            num=filesize;
        fread(pbFile,num,1,pf);
        for(int i=0;i<num;i++)
        {
            while((i<num && pbFile[i]=='>') || bFlag)
            {
                bFlag=true;
                while(i<num && pbFile[i]!='\n')i++;
                if(i<num)
                {
                    bFlag=false;
                    i++;
                }
                else if(i==num)
                    break;
            }
            while(i<num && pbFile[i]!='\r' && pbFile[i]!='\n')
               target[pbFile[i++]-65]++;
        }
        filesize-=num;
    }
    delete []pbFile;
    fclose(pf);

    FILE *p=fopen(argv[2],"r+");
    fprintf(p,"%d",target[0]+target['G'-'A']+target['C'-'A']+target['T'-'A']);
    fclose(p);
    cout<<target[0]+target['G'-'A']+target['C'-'A']+target['T'-'A']<<endl;
    return 0;
}

给你这个参考吧,用法就和你说的一样,命令行参数。
#29
cpp_初学者2011-07-02 23:22
回复 28楼 玩出来的代码
你好,谢谢你噢 :)
我会好好消化您所分享的c++程序...
c和c++,我也有些混淆了 :(

我在使用您的c++程序时,是否该增加"#include <stdio.h> #include <stdlib.h>"在其开头?
程序代码:

#include <stdio.h>
#include <stdlib.h>

int main(int argc,char **argv)
{
    FILE *pf=fopen(argv[1],"rb+");
    fseek(pf,0,SEEK_END);
    int filesize=ftell(pf);
    fseek(pf,0,SEEK_SET);
.
.


谢谢您的确认...
您所写的c++程序,分析数据很快 :)
#30
pangding2011-07-03 10:05
像这种需求简单的位置参数用 玩出来 展示的方法就可以很好的分析出来。
不过一般需要测一测 argv 是不是大于2的,适当检查一下命令行的语法错误。

另外,楼主其实应该也感觉,这种程序就用输入输出重定向就行。让程序处理标准输入输出流是命令行程序的传统(即写成过滤器程序)。

如果对命令行分析有其它更复杂的要求,一般会用一些库来做。posix 标准要求的函数有 getopt(),你可以自己去查一查它的用法。
#31
cpp_初学者2011-07-03 18:17
回复 28楼 玩出来的代码
你好,这是我依照您的代码,所写的程序:
程序代码:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>

int main(int argc,char **argv)
{
    FILE *pf=fopen(argv[1],"rb+");
    fseek(pf,0,SEEK_END);
    int filesize=ftell(pf);
    fseek(pf,0,SEEK_SET);

    int num=1024*1024;
    char *pbFile=new char[num+1];
    bool bFlag=false;
    int target[26]={0};
    if(pbFile==NULL)
    {
        printf("new error");
        return -1;
    }
    while(filesize>0)
    {
        if(filesize<num)
            num=filesize;
        fread(pbFile,num,1,pf);
        for(int i=0;i<num;i++)
        {
            while((i<num && pbFile[i]=='>') || bFlag)
            {
                bFlag=true;
                while(i<num && pbFile[i]!='\n')i++;
                if(i<num)
                {
                    bFlag=false;
                    i++;
                }
                else if(i==num)
                    break;
            }
            while(i<num && pbFile[i]!='\r' && pbFile[i]!='\n')
               target[pbFile[i++]-65]++;
        }
        filesize-=num;
    }
    delete []pbFile;
    fclose(pf);

    FILE *p=fopen(argv[2],"r+");
    fprintf(p,"%d",target[0]+target['G'-'A']+target['C'-'A']+target['T'-'A']);
    fclose(p);
    cout<<target[0]+target['G'-'A']+target['C'-'A']+target['T'-'A']<<endl;
    return 0;
}

不知为何,当我g++此程序时,有一下的错误信息:
程序代码:

read_count.cpp: In function `int main(int, char**)':
read_count.cpp:51: error: `cout' was not declared in this scope
read_count.cpp:51: error: `endl' was not declared in this scope

您知道,该如何解决这问题吗?
以下是我电脑的一些资料:

ia64 GNU/Linux
gcc (GCC) 3.4.6 20060404 (Red Hat 3.4.6-8)

谢谢您的任何意见 :)
#32
specilize2011-07-03 18:47
一直关注着这个帖子,楼主对c++不是十分熟悉,cout和endl都是定义在命名空间std中的,所以要使用cout和endl可以这样
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using std::cout;
using std::endl;
或者是
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
uisng namespace std;
不过后者会污染全局作用域,一般不提倡使用
等楼主熟悉了,发现其实这是很简单而基本的问题
#33
玩出来的代码2011-07-03 20:11
那就用纯C吧,将char *p=new char[num] 改为char *p=malloc(num); delete []p,改为free(p);
cout改为printf.
头文件stdio.h就OK、这实在是不能称为C++程序。也不是一个完整的程序。
#34
pangding2011-07-03 23:02
我想楼主应该是连 C 语言也不会。c++ 不能心急,慢慢学呗。
会其它一些编程语言的话,再学一个一般也不是很费劲。
#35
cpp_初学者2011-07-04 16:09
回复 32楼 specilize
谢谢你的意见,specilize :)
我不是很熟悉c和c++ :(
有点混淆下...
感觉上,perl和c的写法很像...

你说对了...
我犯了一个很基本的错误 :(
忘了加上:
程序代码:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using std::cout;
using std::endl;

唉,真的很大意下...
这是cplusplusprimer书里,有强调要注意的问题 :(
谢谢你的提醒噢...
#36
cpp_初学者2011-07-04 18:19
回复 33楼 玩出来的代码
谢谢你噢..
我现在试着,让您之前写的程序,可以接受及分享更大的输入档案 :)
#37
cpp_初学者2011-07-04 18:21
回复 34楼 pangding
版主,您说对了...
我较熟悉awk,sed,perl.
c和c++,我还是第一次接触 :(
现在还在慢慢的啃着cplusplusprimer2.
c++,还请您多指教 :)
1