熊猫迭代更新列值

Posted

技术标签:

【中文标题】熊猫迭代更新列值【英文标题】:pandas iteratively update column values 【发布时间】:2018-12-29 03:53:54 【问题描述】:

我有一个类似如下的熊猫系列:

a = pd.Series([a1, a2, a3, a4, ...])

我想根据以下规则创建另一个熊猫系列:

b = pd.Series(a1, a2+a1**0.8, a3 + (a2 + a1**0.8)**0.8, a4 + (a3 + (a2 + a1**0.8)**0.8)**0.8, ...).

这使用迭代是可行的,但我有一个大数据集(数百万条记录),我必须执行数千次操作(出于优化目的)。我需要非常快地执行此操作。我有没有可能通过使用pandasnumpy 内置函数来实现这一点?

【问题讨论】:

谢谢。但这里的一个关键区别是 b 的前一个元素是 0.8 的幂,而不是 0.8 的倍数。 【参考方案1】:

你可以使用递归函数,它会在 O(log(n)) 时间内运行

def my_func(x):
    if len(x) == 1:
        b.append(x[0])
        return x[0]
    element = x[-1]+0.8*my_func(x[:-1])
    b.append(element)
    return element
b= []
my_func(list(a))

【讨论】:

我不认为它的运行效率为 O(log(N))。它的效率为 O(N) 而且使用“for循环”比使用递归更好,因为递归涉及出栈和压栈,因此与循环相比效率较低。 哦!所以你的意思是单个for循环总是比递归函数好?在什么情况下递归比循环快? 递归总是比 for 循环慢。只有在使用for循环无法解决问题时才必须使用它。 无论此解决方案是否在运行时方面进行了优化,您都应该知道递归函数会消耗大量内存,这意味着它的内存效率不高。因此,如果这是 OP 的问题,那么您的战斗实际上毫无意义。【参考方案2】:

使用 for 循环

new_series=[]
cur_val=0
for ele in a:
    cur_val=ele+cur_val**0.8
    new_series.append(cur_val)

【讨论】:

@ALollz 谢谢,更新了答案。 我不这么认为,为什么?【参考方案3】:

关于这类问题,您需要了解的重要一点是,您现在正处于一个矛盾的境地。这意味着您正处于一个想要同时利用向量化和非向量化(如线程化或并行化)的点上。

在这种情况下,您可以尝试以下一个/一些选项:

    更改数据结构的类型。

    重新考虑您的问题,看看是否可以完全以矢量化方式解决这个问题(最好)

    仅使用基于非矢量化的方法,但会牺牲其他东西,例如内存。

【讨论】:

【参考方案4】:

与其与问题的根本迭代性质作斗争,不如使用 numba 并尝试做最简单的高性能迭代版本:

@numba.jit(nopython=True)
def epow(vec, p):
    out = np.zeros(len(vec))
    out[0] = vec[0]
    for i in range(1, len(vec)):
        out[i] = vec[i] + (out[i-1])**0.8
    return out

这给了我

In [148]: a1, a2, a3, a4 = range(1, 5)

In [149]: a1, a2+a1**0.8, a3 + (a2 + a1**0.8)**0.8, a4 + (a3 + (a2 + a1**0.8)**0.8)**0.8
Out[149]: (1, 3.0, 5.408224685280692, 7.858724574530816)

In [150]: epow(pd.Series([a1, a2, a3, a4]).values, 0.8)
Out[150]: array([1.        , 3.        , 5.40822469, 7.85872457])

对于更长的系列:

In [151]: s = pd.Series(np.arange(2*10**6))

In [152]: %time epow(s.values, 0.8)
CPU times: user 512 ms, sys: 20 ms, total: 532 ms
Wall time: 531 ms
Out[152]: 
array([0.00000000e+00, 1.00000000e+00, 3.00000000e+00, ...,
       2.11487244e+06, 2.11487348e+06, 2.11487453e+06])

【讨论】:

感谢您的回答。但我发现如果我使用@numba.jit,代码运行速度会更慢。对此有什么可能的解释吗?很抱歉,我是新手。

以上是关于熊猫迭代更新列值的主要内容,如果未能解决你的问题,请参考以下文章

从前一行和特定列值有效地更新熊猫数据框中的 NaN

熊猫填充列值以具有其他列的相似值

熊猫列值到行值

映射列值熊猫[重复]

根据列值加入熊猫数据框

如何将熊猫列的值设置为列表