代码之家  ›  专栏  ›  技术社区  ›  Xukrao

熊猫索引:识别相同值连续重复的子范围

  •  2
  • Xukrao  · 技术社区  · 7 年前

    问题描述

    我正在寻找一种有效的方法来识别 pandas Index 连续重复相同值的对象。

    示例问题

    作为一个简单的例子,请考虑以下内容 指数

    import pandas as pd
    idx = pd.Index(['X', 'C', 'C', 'C', 'Q', 'Q', 'Q', 'Q', 'A', 'P', 'P'])
    

    在本例中,值 C 从位置1到3重复 Q 从位置4到7重复 P 从位置9到10重复。然后我试图得到的结果是一个元组列表(或类似的东西),如下所示:

    [(1, 3, 'C'), (4, 7, 'Q'), (9, 10, 'P')]
    

    到目前为止已经试过了

    我一直在试验 pandas.Index.duplicated 但仅凭这一点,我还未能成功地获得预期的结果。

    编辑:

    指数 X 多次出现):

    idx = pd.Index(['X', 'C', 'C', 'C', 'Q', 'Q', 'Q', 'Q', 'X', 'P', 'P'])
    

    您如何获得忽略 十、 价值观一、 e.如何获得本例的以下结果:

    [(1,3,'C',(4,7,'Q',(9,10,'P')]
    
    2 回复  |  直到 7 年前
        1
  •  5
  •   Brad Solomon    7 年前

    原始问题

    哪里 idx = pd.Index(['X', 'C', 'C', 'C', 'Q', 'Q', 'Q', 'Q', 'A', 'P', 'P']) .

    有点不传统,但应该有效,而且似乎速度要快得多:

    # Get a new Index which is the unique duplicated values in `idx`
    un = idx[idx.duplicated(keep=False)].unique()
    
    # Call `get_loc` on `idx` for each member of `un` above  
    # `np.where` gets position of True in boolean Index
    res = []
    for i in un:
        w = np.where(idx.get_loc(i))[0]
        # w[0], w[-1] analogous to v.min(), v.max() from @MaxU's answer
        res.append((w[0], w[-1], i))
    
    print(res)
    # [(1, 3, 'C'), (4, 7, 'Q'), (9, 10, 'P')]
    

    %timeit myanswer()
    105 µs ± 3.19 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    
    %timeit maxu()
    1.21 ms ± 116 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    

    未注释:

    un = idx[idx.duplicated(keep=False)].unique()
    res = []
    for i in un:
        w = np.where(idx.get_loc(i))[0]
        res.append((w[0], w[-1], i))
    

    已编辑的问题

    哪里 idx = pd.Index(['X', 'C', 'C', 'C', 'Q', 'Q', 'Q', 'Q', 'X', 'P', 'P']) .

    到达 un 这里,首先得到一个布尔索引,当一个值等于它之前或之后的值时,该索引为True,否则为False。这类似于 idx.duplicated(keep=False) 第一部分。

    b = (Series(idx).shift() == idx) | (Series(idx).shift(-1) == idx)
    un = idx[b].unique()
    # Rest should be the same
    
        2
  •  5
  •   MaxU - stand with Ukraine    7 年前

    这里有一种方法:

    In [107]: ix = pd.Series(idx.values)
    
    In [108]: [(v.min(), v.max(),k) for k,v in ix.groupby(ix).groups.items() if len(v) > 1]
    Out[108]: [(1, 3, 'C'), (9, 10, 'P'), (4, 7, 'Q')]