输入一个文件和一个字符统计该字符在文件中出现的次数_统计单词频数

一、引子

假设现在有一个句子,我们需要数出其中每个单词出现的次数。

输入:I have an apple, I have a pineapple, I have a banana.

输出:

I 3

a 2

an 1

apple 1

banana 1

have 3

pineapple 1

1、第一种方法

聪明的小伙伴们,是不是马上就想到了?简单,将句子存成字符串,再转换成列表来统计:

1)将字符串s按空格拆分成列表slist

2)对于列表slist的每个元素:

(1)去除非数字和字母,这里尤其是指"," "."等符号

(2)存入字典counts,key为slist的元素,value是出现次数

def count_words_w1(s):
    slist = s.split()
    counts = dict()
    patn = re.compile("W+")
    for i in slist:
        i = patn.sub("",i)
        counts[i] = counts.get(i,0)+1

    for k,v in sorted(counts.items()):
        print("{0}t{1}".format(k,v))

2、第二种方法

那么如果不转化成列表呢?我们还有别的方法吗?当然有。

对字符串s中每个字符,进行判断:

(1)如果字符是“数字或字母”,则添加到全局变量word尾部

(2)如果字符是“符号或空格”等非数字非字母的形式,则将此时word中保存的单词存入列表counts中

def count_words_w2(s):
    slen = len(s)
    i = 0
    word = ""
    counts = dict()
    while(i<slen):
        if re.match("W+",s[i]):
            if word!="":
                counts[word] = counts.get(word,0)+1
                word = ""
        else:
            word += s[i]
        i+=1
    if word !="":
        counts[word]= counts.get(word,0)+1
    for k,v in sorted(counts.items()):
        print("{0}t{1}".format(k,v))

那么问题就来了,第一种方法已经足够简单明了了,为什么还要自找麻烦,使用第二种方法呢?

现在闭上眼睛,假想我们有一个特别特别长的句子,有多长呢?ennnnn,就3G个字符那么长长长好了,此时我们转换成list就会较慢(时间长),list也会特别大(内存大),而第二种方法省略了转成list的步骤,节省了时间,读一个单词处理一个单词,内存开销自然也少了。

3、总结一下

第一种方法思路直观,简单易懂,但当字符串非常大时,运行速度较慢,占用内存较大;

第二种方法相对复杂,代码数较多,但是当字符串较大时,运行速度较快,占用内存较小。

二、扩展

在实际应用中,请大家思考:

如果有一个WES的BED文件(假设已排序),每一行是一条染色体区间(interval),需要将行与行之间有overlap的记录合并成一条记录,该如何设计程序?

——————————————思考让我变聪明的分割线——————————————

第一个思路是将文件存入dict:key为染色体编号,value为各个[start,end]对,然后利用列表顺序,判断overlap并合并(程序略),当BED较大,区间较多时,可以想见这个dict会非常大。

根据上文,我们用第二种方法来尝试一下:

假设我们的输入文件是:

chr1    0    20
chr1    15    35
chr1    40    50
chr2    0    10
chr2    15    30
chr2    25    60
chr3    10    40

则我们期望的输出文件是:

chr1    0       35
chr1    40      50
chr2    0       10
chr2    15      60
chr3    10      40

1)定义全局变量chrid,start,end和merge_region并初始化,chrid,start和end用于存放上一条合并的interval,列表merge_region用于存放所有合并好的intervals;

2)对于BED文件的每一行,判断当前行interval和全局变量代表的interval是否有overlap,如有,overlap等于1,否则overlap等于-1;

3)当BED读入的不是第一行,且overlap等于-1时(如下图黄色行),说明此时的全局变量合并的interval为最大合并区间,并保存到merge_region中,保存到merge_region中之后,不要忘记重置全局变量(见读入此行后的全局变量);

4)如果BED读入的是第一行,或overlap等于1(如下图非黄色的行),此时需扩展intervals,即,取当前行interval和全局变量interval的并集;

5)最后,完成BED文件读入后,不要忘了保存BED文件最后一行的interval.

9b30a50546ddd1569b7783b096659989.png
def merge_chr_region(bedfile):
    chrid = ""
    start = -1
    end   = -1
    merge_region = list()


    for line in open(bedfile):
        line = line.rstrip()
        cur_chr,cur_start,cur_end = line.split()

        cur_start = int(cur_start)
        cur_end = int(cur_end)

        overlap = get_overlap(cur_start,cur_end,start,end) if chrid==cur_chr else -1
        if chrid!="" and overlap<=0:
            merge_region.append([chrid,start,end])
            chrid = cur_chr
            start = cur_start
            end   = cur_end
        else:
            chrid = cur_chr
            start = min(start,cur_start) if start>=0 else cur_start
            end   = max(end,cur_end)


    if chrid != "":
        merge_region.append([chrid,start,end])
        chrid = ""


    for i in range(len(merge_region)):
        print("t".join(map(str,merge_region[i])))


def get_overlap(cur_start,cur_end,start,end):
    if cur_start<=end and cur_end>=start:
        return 1
    else:
        return -1
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值