numpy数组中的向后计数

Posted

技术标签:

【中文标题】numpy数组中的向后计数【英文标题】:backward count in a numpy array 【发布时间】:2019-10-13 05:01:19 【问题描述】:

假设我有一系列像这样排列在一个 numpy 数组中的整数值。

nan = np.nan
arr = np.array([3, nan, nan, nan, 5, nan, nan, nan, nan, nan])

nan 值应该用从第一个非空值到零的反向计数填充。

[3, 2, 1, 0, 5, 4, 3, 2, 1, 0]

【问题讨论】:

熊猫也有用吗? 没错 【参考方案1】:

IMO,最简单的 pandas 方法是使用 groupbycumcountascending=False

s = pd.Series(np.cumsum(~np.isnan(arr)))
s.groupby(s).cumcount(ascending=False)

0    3
1    2
2    1
3    0
4    5
5    4
6    3
7    2
8    1
9    0
dtype: int64

【讨论】:

@QuangHoang 抱歉,我不确定我是否关注。它用(递减的)计数标记每个组中的行。 对不起,我一定是在做白日梦。 +1【参考方案2】:

这是一个带有 NumPy 的矢量化 -

def backward_count(a):
    m = ~np.isnan(a)
    idx = np.flatnonzero(m)

    p = np.full(len(a), -1, dtype=a.dtype)
    p[idx[0]] = a[idx[0]]+idx[0]

    d = np.diff(idx)
    p[idx[1:]] = np.diff(a[m]) + d - 1
    out = p.cumsum()
    out[:idx[0]] = np.nan
    return out

使用更通用的案例运行示例 -

In [238]: a
Out[238]: array([nan,  3., nan,  5., nan, 10., nan, nan,  4., nan, nan])

In [239]: backward_count(a)
Out[239]: array([nan,  3.,  2.,  5.,  4., 10.,  9.,  8.,  4.,  3.,  2.])

基准测试

通过10,000x 放大给定样本的设置-

In [240]: arr = np.array([3, nan, nan, nan, 5, nan, nan, nan, nan, nan])

In [241]: arr = np.tile(arr,10000)

# Pandas based one by @cs95
In [243]: %%timeit
     ...: s = pd.Series(np.cumsum(~np.isnan(arr)))
     ...: s.groupby(s).cumcount(ascending=False)
35.9 ms ± 258 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [245]: %timeit backward_count(arr)
3.04 ms ± 4.35 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

【讨论】:

【参考方案3】:
import pandas as pd
import numpy as np
import math

arr = pd.Series([3,np.nan,np.nan,np.nan,5,np.nan,np.nan,np.nan,np.nan,np.nan])

for i in range(len(arr)):
    # Check if each element is "NaN"
    if math.isnan(arr[i]):
        # If NaN then take the previous element and subtract 1
        arr[i] = arr[i-1]-1

# print the final array
print(arr)

结果:

0    3.0
1    2.0
2    1.0
3    0.0
4    5.0
5    4.0
6    3.0
7    2.0
8    1.0
9    0.0
dtype: float64

【讨论】:

1) 你没有解释你的代码(是的,这对我来说很明显,但对每个阅读它的人来说都不是),2) 在 numpy 中使用循环是禁忌。 我自己是 numpy 新手,为什么循环不好? NumPy 操作被实现为比循环更快、更具可扩展性。该过程称为"vectorisation",在性能方面比循环高出几步。

以上是关于numpy数组中的向后计数的主要内容,如果未能解决你的问题,请参考以下文章

第一章 科学计数工具numpy numpy数据结构基础

将数据帧转换为 numpy 数组会导致所有数字以科学计数法打印 [关闭]

python numpy基础 数组和矢量计算

Android Studio 中的向后兼容性是啥?

Numpy学习之

如何处理 UIPageViewController 中的向后滚动?