【问题标题】:python3 counter that also averages index location in a sliding windowpython3计数器,它也平均滑动窗口中的索引位置
【发布时间】:2020-05-11 19:45:49
【问题描述】:

我有一个列表和一个字符串:

anchors=['a','b']
mystring = 'aerdsbewsabsdsasdbs'

我想遍历mystring 中的每个字母,如果我“击中”一个锚点,请跟踪出现在“prior”之前的 2 个字母和“post”之后的 2 个字母的字母。

所以我想要的输出将是一个列表列表,格式为:

[[prior letters, anchor, post letters],
prior letters, anchor, post letters]]

对于每个锚。这可以通过在letters 内的mystring 上使用Counter() 轻松实现,但我想按平均索引位置对结果输出进行排序。
因此,对于每个先前的字母,我想计算它在每个锚点的 2 个字母内出现的次数,并按锚点的索引位置的平均值进行排序。在我的锚点“a”的示例中,这看起来像:

prior letters = {s:(2,-1), w:(1,-2), d:(1,-2)}
anchor = 'a'
post letters = {e:(1,1), r:(1,2), b:(1,1), s:(2,1.5), d:(1,2)}

前面和后面字母的每个键值对都采用以下形式:

letter:(count,avg_index)

字母=2的滑动窗口内的字母
count = 字母在每个锚点的滑动窗口中出现的次数
avg_index = 字母相对于每个锚点的平均索引位置,例如 (-1.5) 表示字母出现在位置 -1 和 -2,平均为 -1.5。
我正在努力完成代码,有没有更好的数据结构可以帮助我?

【问题讨论】:

    标签: python python-3.x data-structures counter


    【解决方案1】:

    不是一个完整的答案,但评论太窄了。 我已经测试了这段代码:

    import pandas as pd
    
    anchors=['a','b']
    mystring = 'aerdsbewsabsdsasdbs'
    
    df = pd.DataFrame(columns=['letter', 'match_anchor', '2_letters_before', '2_letters_afer'])
    for letter in mystring:
        df = df.append( pd.DataFrame([[letter, letter in anchors]], columns=['letter', 'match_anchor']) )
    
    df['2_letters_before'] = df['letter'].shift(2)
    df['2_letters_afer'] = df['letter'].shift(-2)
    df = df[df['match_anchor'] == True]
    df = df.reset_index(drop=True)
    print(df)
    

    输出是:

      letter match_anchor 2_letters_before 2_letters_afer
    0      a         True              NaN              r
    1      b         True                d              w
    2      a         True                w              s
    3      b         True                s              d
    4      a         True                d              d
    5      b         True                s            NaN
    

    关键是我不了解您的数据。有了当前的输出,我想我已经接近你的期望了。但是,您能否解释更多您想要的预期输出?例如,数字 (2,-1) 对字母 's'/anchor 'a' 的含义是什么?

    prior letters = {s:(2,-1), w:(1,-2), d:(1,-2)}
    anchor = 'a'
    post letters = {e:(1,1), r:(1,2), b:(1,1), s:(2,1.5), d:(1,2)}
    

    编辑: 好吧,不是一个非常pythonic的代码,但我已经设法用pandas做到了。 第一步:我正在构建一个 DataFrame,其中的字母与窗口内的锚点 + 字母匹配。 然后,我构建了所有要查找的字母的列表。我确实遍历这些字母以计算它们+计算索引。 输出不是字典,但我只打印了值。它可以轻松编辑以满足您的需求。

    import pandas as pd
    import numpy as np
    
    anchors=['a','b']
    mystring = 'aerdsbewsabsdsasdbs'
    
    # Building the DataFrame for calculations:
    df = pd.DataFrame(columns=['letter', 'match_anchor'])
    for letter in mystring:
        df = df.append( pd.DataFrame([[letter, letter in anchors]], columns=['letter', 'match_anchor']) )
    
    df['2_let_bef'] = df['letter'].shift(2)
    df['1_let_bef'] = df['letter'].shift(1)
    df['1_let_aft'] = df['letter'].shift(-1)
    df['2_let_aft'] = df['letter'].shift(-2)
    df = df[df['match_anchor'] == True]
    print(df)
    
    # Getting the list of letters to look to:
    let = pd.concat([df['2_let_bef'],
                     df['1_let_bef'],
                     df['2_let_aft'],
                     df['1_let_aft'],], ignore_index=True)
    let = let.dropna().unique().tolist()
    print('list of letters to look to:', let, '\n')
    
    # looping through
    for letter in anchors:
        print('\nAnchor=', letter)
        pf_anchor = df[df['letter'] == letter]
        # checking 'before'
        for l in let:
            count = len(pf_anchor[pf_anchor['2_let_bef'] == l]) + \
                    len(pf_anchor[pf_anchor['1_let_bef'] == l])
            index_avg = -2*len(pf_anchor[pf_anchor['2_let_bef'] == l]) - \
                        len(pf_anchor[pf_anchor['1_let_bef'] == l])
            if count > 0:
                index_avg = index_avg/count
                print('(before)', l, ":", (count,index_avg))
    
        for l in let:
        # checking 'after'
            count = len(pf_anchor[pf_anchor['2_let_aft'] == l]) + \
                    len(pf_anchor[pf_anchor['1_let_aft'] == l])
            index_avg = 2*len(pf_anchor[pf_anchor['2_let_aft'] == l]) + \
                        len(pf_anchor[pf_anchor['1_let_aft'] == l])
            if count > 0:
                index_avg = index_avg/count
                print('(after)', l, ":", (count,index_avg))
    

    输出:

    Anchor= a
    (before) d : (1, -2.0)
    (before) w : (1, -2.0)
    (before) s : (2, -1.0)
    (after) d : (1, 2.0)
    (after) s : (2, 1.5)
    (after) r : (1, 2.0)
    (after) e : (1, 1.0)
    (after) b : (1, 1.0)
    
    Anchor= b
    (before) d : (2, -1.5)
    (before) s : (3, -1.6666666666666667)
    (before) a : (1, -1.0)
    (after) d : (1, 2.0)
    (after) w : (1, 2.0)
    (after) s : (2, 1.0)
    (after) e : (1, 1.0)
    

    【讨论】:

    • 感谢奥利维尔!我将用更多解释更新我的帖子 - 我的预期输出中的元组是 (count,avg_index) 与锚点相关的每个字母。
    【解决方案2】:

    我能够在没有 pandas/numpy 的情况下编写它以获得更 Pythonic 的答案,但接受了 Oliviers,因为他首先得到它并且它有效。

    from collections import Counter, defaultdict
    from statistics import mean
    mytext = 'sldksfjksljdkljasflkjsfdjkldfslkjsfdsaljkdfsljkbfdsjlkdfs'
    anchors = ['k','s']
    out = []
    letters = []
    amount=0
    avgindex=0
    for anchor in anchors:
        anchordict = {anchor:(amount,avgindex)}
        letterindex = defaultdict(list)
        for i,letter in enumerate(mytext):
            if anchor==letter:
                z=-2
                for letter in mytext[i-2:i]:
                    letterindex[letter].append(z)
                    z=z+1
                anchordict[anchor] = (anchordict[anchor][0]+1,anchordict[anchor][1]+1)
        out.append(anchordict)
        for k,v in letterindex.items():
            letterindex[k] = mean(v)
        for k,v in letterindex.items():
            letters.append([anchor,k,v])
    letters.sort(key=lambda tup: tup[2])
    print(out)
    print(letters)
    

    【讨论】:

      猜你喜欢
      • 2017-03-12
      • 2021-09-01
      • 2018-02-11
      • 2020-07-05
      • 2011-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-29
      相关资源
      最近更新 更多