微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在pandas索引中累积唯一的列总和

我有一个pandas DateFrame,我创建的df

df = pd.read_table('sorted_df_changes.txt', index_col=0, parse_dates=True, names=['date', 'rev_id', 'score'])

其结构如下:

                     page_id     score  
date
2001-05-23 19:50:14  2430        7.632989
2001-05-25 11:53:55  1814033     18.946234
2001-05-27 17:36:37  2115        3.398154
2001-08-04 21:00:51  311         19.386016
2001-08-04 21:07:42  314         14.886722

date是索引,属于DatetimeIndex类型.

每个page_id可能出现在一个或多个日期(不是唯一的)中,并且大小约为100万.所有页面一起组成文档.

我需要在每个日期获得整个文档的分数,同时只计算任何给定page_id的最新分数.

示例数据

                     page_id     score  
date
2001-05-23 19:50:14  1           3
2001-05-25 11:53:55  2           4
2001-05-27 17:36:37  1           5
2001-05-28 19:36:37  1           1

示例解决方

                     score  
date
2001-05-23 19:50:14  3
2001-05-25 11:53:55  7 (3 + 4)
2001-05-27 17:36:37  9 (5 + 4)
2001-05-28 19:36:37  5 (1 + 4)

2的条目被连续计数,因为它没有重复,但每次重复id 1时,新的分数取代旧的分数.

解决方法:

编辑:

最后,我找到了一个不需要循环的解决方案:

df.score.groupby(df.page_id).transform(lambda s:s.diff().combine_first(s)).cumsum()

我认为需要一个for循环:

from StringIO import StringIO
txt = """date,page_id,score
2001-05-23 19:50:14,  1,3
2001-05-25 11:53:55,  2,4
2001-05-27 17:36:37,  1,5
2001-05-28 19:36:37,  1,1
2001-05-28 19:36:38,  3,6
2001-05-28 19:36:39,  3,9
"""

df = pd.read_csv(StringIO(txt), index_col=0)

def score_sum_py(page_id, scores):
    from itertools import izip
    score_sum = 0
    last_score = [0]*(np.max(page_id)+1)
    result = np.empty_like(scores)
    for i, (pid, score) in enumerate(izip(page_id, scores)):
        score_sum = score_sum - last_score[pid] + score
        last_score[pid] = score
        result[i] = score_sum
    result.name = "score_sum"
    return result

print score_sum_py(pd.factorize(df.page_id)[0], df.score)

输出

date
2001-05-23 19:50:14     3
2001-05-25 11:53:55     7
2001-05-27 17:36:37     9
2001-05-28 19:36:37     5
2001-05-28 19:36:38    11
2001-05-28 19:36:39    14
Name: score_sum

如果python中的循环很慢,你可以尝试将两个系列page_id,得分转换为python列表,循环列表和使用python的本机整数计算可能更快.

如果速度很重要,你也可以试试cython:

%%cython
cimport cython
cimport numpy as np
import numpy as np

@cython.wraparound(False) 
@cython.boundscheck(False)
def score_sum(np.ndarray[int] page_id, np.ndarray[long long] scores):
    cdef int i
    cdef long long score_sum, pid, score
    cdef np.ndarray[long long] last_score, result

    score_sum = 0
    last_score = np.zeros(np.max(page_id)+1, dtype=np.int64)
    result = np.empty_like(scores)

    for i in range(len(page_id)):
        pid = page_id[i]
        score = scores[i]
        score_sum = score_sum - last_score[pid] + score
        last_score[pid] = score
        result[i] = score_sum

    result.name = "score_sum"
    return result

这里我使用pandas.factorize()将page_id转换为范围为0和N的数组.其中N是page_id中元素的唯一计数.您还可以使用dict缓存每个page_id的last_score,而无需使用pandas.factorize().

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐