2017-01-13 59 views
3

我遍历单词列表来查找单词之间最常用的字符(即在列表中[hello, hank],'h'计数为出现两次,而'l'计为出现一次。 )。一个python列表工作正常,但我也在研究NumPy(dtype数组?)和Pandas。看起来Numpy可能会走,但是还有其他的软件包需要考虑吗?我该怎样才能使这个功能更快?迭代字符串列表中的字符的最快对象

守则问:

def mostCommon(guessed, li): 
    count = Counter() 
    for words in li: 
      for letters in set(words): 
       count[letters]+=1 
    return count.most_common()[:10] 

感谢。

+0

灿你解释“最常见的独特性格”是什么意思?并包含一些示例输入和输出数据 –

+0

@Chris_Rands如果您需要更多,请使用示例编辑lmk。 – ZtoYi

+0

所以你只想要最频繁的角色或所有角色的频率? –

回答

3

下面是使用它的views-concept一个NumPy的方法 -

def tabulate_occurrences(a):   # Case sensitive 
    chars = np.asarray(a).view('S1') 
    valid_chars = chars[chars!=''] 
    unqchars, count = np.unique(valid_chars, return_counts=1) 
    return pd.DataFrame({'char':unqchars, 'count':count}) 

def topNchars(a, N = 10):    # Case insensitive 
    s = np.core.defchararray.lower(a).view('uint8') 
    unq, count = np.unique(s[s!=0], return_counts=1) 
    sidx = count.argsort()[-N:][::-1] 
    h = unq[sidx] 
    return [str(unichr(i)) for i in h] 

采样运行 -

In [322]: a = ['er', 'IS' , 'you', 'Is', 'is', 'er', 'IS'] 

In [323]: tabulate_occurrences(a) # Case sensitive 
Out[323]: 
    char count 
0 I  3 
1 S  2 
2 e  2 
3 i  1 
4 o  1 
5 r  2 
6 s  2 
7 u  1 
8 y  1 

In [533]: topNchars(a, 5)   # Case insensitive 
Out[533]: ['s', 'i', 'r', 'e', 'y'] 

In [534]: topNchars(a, 10)  # Case insensitive 
Out[534]: ['s', 'i', 'r', 'e', 'y', 'u', 'o'] 
+0

Hm。我只是计时,看起来比常规列表解决方案慢。 – ZtoYi

+0

@ZtoYi您是否需要实际发生的前10位字符的计数,或者只是想查找这些字符? – Divakar

+0

只是人物会很好。 – ZtoYi

-1

只是做

counter = Counter(''.join(li)) 
most_common = counter.most_common() 

,大功告成

0

这看起来是非常快的已经,并在O(n)运行。我所看到的唯一真正的改进机会是将li分成多个部分,从而将此过程并行化。

+0

这是一个O(n)的问题,但想知道是否使用不同的对象可能有助于提高速度。 (即这篇文章http://stackoverflow.com/questions/993984/why-numpy-instead-of-python-lists) – ZtoYi

3

选项1

def pir1(li): 
    sets = [set(s) for s in li] 
    ul = np.array(list(set.union(*sets))) 
    us = np.apply_along_axis(set, 1, ul[:, None]) 
    c = (sets >= us).sum(1) 
    a = c.argsort()[:-11:-1] 
    return ul[a] 

选项2

def pir2(li): 
    return Counter(chain.from_iterable([list(set(i)) for i in li])).most_common(10) 

假设单词列表li

import pandas as pd 
import numpy as np 
from string import ascii_lowercase 

li = pd.DataFrame(
    np.random.choice(list(ascii_lowercase), (1000, 10)) 
).sum(1).tolist() 

包括Divakar的和OP的功能

def tabulate_occurrences(a): 
    chars = np.asarray(a).view('S1') 
    valid_chars = chars[chars!=''] 
    unqchars, count = np.unique(valid_chars, return_counts=1) 
    return pd.DataFrame({'char':unqchars, 'count':count}) 

def topNchars(a, N = 10): 
    s = np.core.defchararray.lower(a).view('uint8') 
    unq, count = np.unique(s[s!=0], return_counts=1) 
    sidx = count.argsort()[-N:][::-1] 
    h = unq[sidx] 
    return [str(chr(i)) for i in h] 

def mostCommon(li): 
    count = Counter() 
    for words in li: 
      for letters in set(words): 
       count[letters]+=1 
    return count.most_common()[:10] 

测试

import pandas as pd 
import numpy as np 
from string import ascii_lowercase 
from timeit import timeit 

results = pd.DataFrame(
    index=pd.RangeIndex(5, 405, 5, name='No. Words'), 
    columns=pd.Index('pir1 pir2 mostCommon topNchars'.split(), name='Method'), 
) 

np.random.seed([3,1415]) 
for i in results.index:  
    li = pd.DataFrame(
     np.random.choice(list(ascii_lowercase), (i, 10)) 
    ).sum(1).tolist() 
    for j in results.columns: 
     v = timeit(
      '{}(li)'.format(j), 
      'from __main__ import {}, li'.format(j), 
      number=100 
     ) 
     results.set_value(i, j, v) 

ax = results.plot(title='Time Testing') 
ax.set_ylabel('Time of 100 iterations') 

enter image description here

+0

所以,最后的O/P将是一个最大的字符,对不对? – Divakar

+0

@Divakar基于他们的代码,他们想要前10名。同时评论其他答案“如果我希望下一个最频繁的?” – piRSquared

+0

@piRSquared当你吐出来的时候,我正在尝试这些选项。谢谢!你能按照我能得到前10名字符的方式排序它们吗(关系不重要)?谢谢。 – ZtoYi

2

假设你只需要最常见的字符,每个字符只有每字计数一次:

>>> from itertools import chain 
>>> l = ['hello', 'hank'] 
>>> chars = list(chain.from_iterable([list(set(word)) for word in l])) 
>>> max(chars, key=chars.count) 
'h' 

使用maxlist.count比使用Counter快了很多,由于C级执行。

+0

如果我想要下一个最频繁的信件,该怎么办? – ZtoYi

+0

@ZtoYi然后你可能不想使用这种方法;尽管仍然有可能,但可以使用'heapq'或者对'chars'列表进行排序,但是两者都会增加相当多的开销 –

0

这里是uniqueifies每个字符串一个纯Python的解决方案,加入集合,然后计算结果(使用Divakar的例子列表)

>>> li=['er', 'IS' , 'you', 'Is', 'is', 'er', 'IS'] 
>>> Counter(e for sl in map(list, map(set, li)) for e in sl) 
Counter({'I': 3, 'e': 2, 's': 2, 'S': 2, 'r': 2, 'o': 1, 'i': 1, 'u': 1, 'y': 1}) 

如果你想上限和下限案件算作同一封信:

>>> Counter(e for sl in map(list, map(set, [s.lower() for s in li])) for e in sl) 
Counter({'i': 4, 's': 4, 'e': 2, 'r': 2, 'o': 1, 'u': 1, 'y': 1}) 

现在,让我们一次:

from __future__ import print_function 
from collections import Counter 
import numpy as np 
import pandas as pd 

def dawg(li): 
    return Counter(e for sl in map(list, map(set, li)) for e in sl) 

def nump(a): 
    chars = np.asarray(a).view('S1') 
    valid_chars = chars[chars!=''] 
    unqchars, count = np.unique(valid_chars, return_counts=1) 
    return pd.DataFrame({'char':unqchars, 'count':count}) 

if __name__=='__main__': 
    import timeit 
    li=['er', 'IS' , 'you', 'Is', 'is', 'er', 'IS'] 
    for f in (dawg, nump): 
     print(" ",f.__name__, timeit.timeit("f(li)", setup="from __main__ import f, li", number=100)) 

结果:

dawg 0.00134205818176 
nump 0.0347728729248 

Python的解决方案显著加快在这种情况下

相关问题