【问题标题】:find max per column of values that come before the min找到最小值之前的每列值的最大值
【发布时间】:2016-11-18 06:50:12
【问题描述】:

考虑数组a

a = np.array([
        [5, 4],
        [4, 5],
        [2, 2],
        [6, 1],
        [3, 7]
    ])

我可以找到最小值在哪里

a.argmin(0)

array([2, 3])

如何找到索引 2 之前的第 0 列值的最大值。第 1 列和索引 3 也是如此。更重要的是,它们在哪里?

如果我这样做

a.max(0)

array([6, 7])

但我需要

# max values
array([5, 5])

# argmax before mins
array([0, 1])

【问题讨论】:

    标签: python pandas numpy


    【解决方案1】:

    这是使用broadcasting 的一种方法-

    b = np.where(a.argmin(0) >= np.arange(a.shape[0])[:,None],a,np.nan)
    idx = np.nanargmax(b,axis=0)
    out = a[idx,np.arange(a.shape[1])]
    

    示例运行 -

    In [38]: a
    Out[38]: 
    array([[5, 4],
           [4, 5],
           [2, 2],
           [6, 1],
           [3, 7]])
    
    In [39]: b = np.where(a.argmin(0) >= np.arange(a.shape[0])[:,None],a,np.nan)
        ...: idx = np.nanargmax(b,axis=0)
        ...: out = a[idx,np.arange(a.shape[1])]
        ...: 
    
    In [40]: idx
    Out[40]: array([0, 1])
    
    In [41]: out
    Out[41]: array([5, 5])
    

    或者,如果a只有正数,我们可以简单地得到idx -

    mask = a.argmin(0) >= np.arange(a.shape[0])[:,None]
    idx = (a*mask).argmax(0)
    

    【讨论】:

    • 不错!将其余部分设置为np.nan 非常聪明。收藏问题以供将来参考!谢谢@Divakar。
    • 如果您好奇,我发布了另一个答案。
    【解决方案2】:

    我知道我可以用累积的argmax@ajcr 的矢量化版本来回答这个问题answered that question for me here

    def ajcr(a):
        m = np.maximum.accumulate(a)
        x = np.repeat(np.arange(a.shape[0])[:, None], a.shape[1], axis=1)
        x[1:] *= m[:-1] < m[1:]
        np.maximum.accumulate(x, axis=0, out=x)
        # at this point x houses the cumulative argmax
        # we slice that with a's argmin
        return x[a.argmin(0), np.arange(a.shape[1])]
    
    def divakar(a):
        b = np.where(a.argmin(0) >= np.arange(a.shape[0])[:,None],a,np.nan)
        return np.nanargmax(b,axis=0)
    

    比较

    a = np.random.randn(10000, 1000)
    (ajcr(a) == divakar(a)).all()
    
    True
    

    时机

    import timeit
    
    results = pd.DataFrame(
        [], [10, 100, 1000, 10000],
        pd.MultiIndex.from_product(
            [['divakar', 'ajcr'], [10, 100, 1000]]))
    
    for i, j in results.stack(dropna=False).index:
        a = np.random.randn(i, j)
        results.loc[i, ('divakar', j)] = \
            timeit.timeit(
                'divakar(a)',
                setup='from __main__ import divakar, a',
                number=10)
        results.loc[i, ('ajcr', j)] = \
            timeit.timeit(
                'ajcr(a)',
                setup='from __main__ import ajcr, a',
                number=10)
    
    import matplotlib.pyplot as plt
    
    fig, axes = plt.subplots(2, 2, figsize=(10, 5))
    for i, (name, group) in enumerate(results.stack().groupby(level=0)):
        r, c = i // 2, i % 2
        group.xs(name).plot.barh(ax=axes[r, c], title=name)
    fig.tight_layout()
    

    results
    

    【讨论】:

    • 啊我不知道这两个问题有联系。另一个问题似乎更难解决,但你得到了一个很好的解决方案。很高兴看到其他方法可以到达这个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-21
    • 2018-03-12
    • 1970-01-01
    • 2023-03-08
    • 2014-12-15
    • 2015-01-09
    • 1970-01-01
    相关资源
    最近更新 更多