【问题标题】:Convert list of tuples into list of slices to use with np.r_将元组列表转换为切片列表以与 np.r_ 一起使用
【发布时间】:2021-04-02 11:09:49
【问题描述】:

在 pandas 中工作时,我创建了一个元组列表,表示围绕给定索引点集的一系列行:

mask = df.loc[df['Illustration']=='Example'].index
idxlist = [(i-1,i+10) for i in mask]
idxlist
[(2, 13), (48, 59), (120, 131),...]

我想使用这个元组列表中的值作为范围切片索引来调用np.r_,它采用这种类型的列表:

df.iloc[np.r_[2:13, 48:59, 120:131,...] 

我可以通过slice 函数传递我的元组列表:

slicelist = [slice(*(idxlist[j])) for j in range(len(idxlist))]

但是 slicenp.r_ 不(据我所知)相互兼容。

所以我正在寻找一种将元组列表转换为切片范围列表的方法,或者一种使用列表推导生成切片范围列表的方法,类似于我在上面制作 idxslice 所做的.我知道我可以找到一些非常不雅的方法来做到这一点,但我正在寻找最 Pythonic 的方式,最好没有循环。谢谢。

【问题讨论】:

    标签: python pandas numpy slice


    【解决方案1】:
    In [208]: alist = [(2, 13), (48, 59), (120, 131)]
    

    r_ 使用索引表示法将切片列表转换为索引(它实际上是具有__getitem__ 方法的类实例。解释器将n:m 转换为slice(n,m),但r_ 然后将其转换为arange(n,m).

    In [209]: np.r_[2:13, 48:59, 120:131]
    Out[209]: 
    array([  2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  48,  49,
            50,  51,  52,  53,  54,  55,  56,  57,  58, 120, 121, 122, 123,
           124, 125, 126, 127, 128, 129, 130])
    

    s_ 可以使用相同的输入,但会生成切片对象:

    In [211]: np.s_[2:13, 48:59, 120:131]
    Out[211]: (slice(2, 13, None), slice(48, 59, None), slice(120, 131, None))
    

    与(并具有相同的迭代)相同:

    In [212]: [slice(i,j) for i,j in alist]
    Out[212]: [slice(2, 13, None), slice(48, 59, None), slice(120, 131, None)]
    

    arange替换slice

    In [213]: [np.arange(i,j) for i,j in alist]
    Out[213]: 
    [array([ 2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12]),
     array([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58]),
     array([120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130])]
    

    加入它们会产生与r_相同的结果:

    In [214]: np.hstack(_)
    Out[214]: 
    array([  2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  48,  49,
            50,  51,  52,  53,  54,  55,  56,  57,  58, 120, 121, 122, 123,
           124, 125, 126, 127, 128, 129, 130])
    

    r_ 很漂亮,但在计算上却是一样的。像这样的列表理解并没有什么不优雅或不符合 Python 的地方。

    由于每个范围的长度相同(11 个值),我们也可以使用linspace

    In [220]: np.linspace((2,48,120),(13,59,131),11,endpoint=False, dtype=int)
    Out[220]: 
    array([[  2,  48, 120],
           [  3,  49, 121],
           [  4,  50, 122],
           [  5,  51, 123],
           [  6,  52, 124],
           [  7,  53, 125],
           [  8,  54, 126],
           [  9,  55, 127],
           [ 10,  56, 128],
           [ 11,  57, 129],
           [ 12,  58, 130]])
    In [221]: np.hstack(_.T)
    Out[221]: 
    array([  2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  48,  49,
            50,  51,  52,  53,  54,  55,  56,  57,  58, 120, 121, 122, 123,
           124, 125, 126, 127, 128, 129, 130])
    

    您仍然可以使用r_alist(但使用arange 更直接):

    In [225]: np.r_.__getitem__(tuple([slice(i,j) for i,j in alist]))
    Out[225]: 
    array([  2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  48,  49,
            50,  51,  52,  53,  54,  55,  56,  57,  58, 120, 121, 122, 123,
           124, 125, 126, 127, 128, 129, 130])
    

    np.r_ 只是伪装成索引的concatenate(添加了一些铃声):

    np.r_[tuple([np.arange(i,j) for i,j in alist])]
    np.hstack([np.arange(i,j) for i,j in alist])
    

    【讨论】:

    • 超越使命召唤!这类教学回复总是受到真诚的赞赏;非常感谢。
    【解决方案2】:

    不需要太花哨,因为索引遵循一个模式,只需列出所有索引。

    from itertools import chain
    
    #mask = [3, 49, 121, ...]
    m = [*chain.from_iterable([range(i-1, i+10) for i in mask])]
    
    # or simply
    m = [x for i in mask for x in range(i-1, i+10)]
    
    # Then
    df.iloc[m]
    

    【讨论】:

    • 不错。所以基本上我需要再往后退一步,从那个层面重新思考。太好了,谢谢。
    【解决方案3】:

    完整的 numpy 解决方案:

    import numpy as np    
    indices = np.array(np.concatenate([np.arange(i,j) for i, j in idxlist]))
    df.iloc[indices]
    

    【讨论】:

    • 根据@hpaulj 的解释,这个解决方案特别有意义。谢谢。
    【解决方案4】:

    只是想添加一个不同的答案,它仍然需要一个循环,但您可以堆叠从解包范围获得的 numpy 数组。

    np.hstack([np.fromiter(range(*i), dtype=int, count=len(range(*i))) for i in idx])
    

    【讨论】:

      【解决方案5】:

      我喜欢

       alist = [(2, 13), (48, 59), (120, 131)]
        #print(alist)
       results=[np.arange(x[0],x[1]) for x in alist]
       print(results)
      

      【讨论】:

        【解决方案6】:

        您也可以使用元组对数据进行切片

        data=[x for x in np.arange(131)]
        
        idxlist=[(2, 13), (48, 59), (120, 131)]
         data=[x for x in np.arange(131)]
        
         for tupleSlice in idxlist:
             print(data[tupleSlice[0]:tupleSlice[1]])
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-06-05
          • 1970-01-01
          • 2016-09-28
          • 2018-12-19
          • 1970-01-01
          相关资源
          最近更新 更多