【问题标题】:How to convert cumulative data to daily one?如何将累积数据转换为每日数据?
【发布时间】:2016-08-16 10:43:27
【问题描述】:

我有一个按链接和数据传输开始和结束时间段的累积传输数据列表。换句话说,times 的元素是天数; data 的元素是通过此链接传输到当前传输结束的所有数据的总和:

data = [0.85, 1.6, 1.85, 2.89, 3.56, 4.05, 5.56, 7.89]
times = [[0.5, 1.3], [1.8, 2.1], [2.9, 2.99], [3.5, 3.59], [3.6, 4.1], [4.2, 4.35], [4.65, 4.76], [4.85, 5.5]]

是否有任何 python 或 numpy 方法如何将累积数据转换为传输数据的每日 ([0, 1], [1, 2], [2, 3], [3, 4,], [4, 5], [5, 6]) 统计信息?

P.S 每日数据是指在0 和1 期间(1 和2 等)之间传输了多少数据。

例如,我想查找在0 day 和1 day 之间传输的数据。在[0.5, 1.3]0.85 GB 期间传输的数据。所以我必须找到0.85 GB 的份额,特别是在[0, 1] 之间转移。
0.85 GB * (1-0.5) days / (1.3-0.5) days = 0.53 GB 等等。

【问题讨论】:

  • 这里的“每天”是什么意思?
  • 那么,示例案例的预期输出是什么?
  • @Divakar 再次更新
  • 好的,现在这有点令人困惑。来自data 的0.85 与[0.5, 1.3] 是如何对应的?是因为0.85 是data 中的第一个元素吗?所以,根据这个理论,我们应该让data 和times 中的元素数量相同,而不是data 有8 个元素,而times 有7 个元素。
  • @Divakar 是的。已编辑。这意味着有人在0.5时刻开始发送0.85 GB,并在1.3时刻完成。

标签: python numpy inverse cumulative-sum


【解决方案1】:

您可以使用np.split 将数据分块到每日数组中。首先,您需要定义每天边缘的索引;为此,您可以使用np.histogram 定义代表您日子边缘的垃圾箱。然后 cumsum 得到每天边缘的索引。

hist, bins = np.histogram(times, bins=range(5)) # 5 is number of days
chunked = np.split(data, hist.cumsum())

Chunked 现在应该是一个数组列表,其中每个数组都包含每天的值。你可以应用任何你想要的缩减函数。

print(chunked)   
# [array([0.85]), array([1.6, 1.85]), ...]

map(np.sum, chunked)

请注意,必须对时间/值数组进行排序才能进行拆分。

...

可读性更强但速度慢得多,您可以选择每天的数据。

days = np.floor(times)
chunked = [data[days == day] for day in range(5)]

【讨论】:

  • 是否有可能考虑到一些转移从0 日开始并在1 日结束的事实?
  • 我不知道你会如何以一种麻木的方式做到这一点。但是您的问题正朝着对您要解决的任务非常特殊的方向发展(即对 SO 的其他用户没有用)。你应该准备一些笔和纸并想出一个解决方案,然后你可以询问如何使用 numpy 优化任何慢代码。
【解决方案2】:

@Divakar 已经发布了正确的 numpy 解决方案,这是一个简单的 python 解决方案:

import math
data = [0.85, 1.6, 1.85, 2.89, 3.56, 4.05, 5.56, 7.89]
times = [0.5, 1.3, 1.8, 2.9, 3.5, 3.6, 4.2, 4.65]
daily = [0] * 7

for i, t in enumerate(times):
    daily[int(math.floor(t))] += data[i]

print daily

【讨论】:

    【解决方案3】:

    IIUC 你可以这样做 -

    lims = np.arange(data.size)+1
    col0 = lims - times[:,0]
    col1 = times[:,1] - lims
    lens = times[:,1] - times[:,0]
    
    out = data*col0/lens
    shares = data*(col1/lens)
    out[1:] += shares.cumsum()[:-1]
    

    示例运行 -

    In [144]: data
    Out[144]: array([ 0.85,  1.6 ,  1.85,  2.89,  3.56,  4.05,  5.56,  7.89])
    
    In [145]: times
    Out[145]: 
    array([[ 0.5 ,  1.3 ],
           [ 1.8 ,  2.1 ],
           [ 2.9 ,  2.99],
           [ 3.5 ,  3.59],
           [ 3.6 ,  4.1 ],
           [ 4.2 ,  4.35],
           [ 4.65,  4.76],
           [ 4.85,  5.5 ]])
    
    In [146]: out
    Out[146]: 
    array([   0.53125   ,    1.38541667,    2.90763889,   16.70208333,
             -2.55102778,   29.67297222,   55.3047904 , -138.46269211])
    

    【讨论】:

    • 第一个元素是正确的......但其他元素如 118、38、16、48 uhhh
    • @RomaKarageorgievich 解释示例案例中第二个元素的预期输出?
    • 在1 和2 之间传输了多少数据。所以我们有两个周期 [0.5, 1.3] 和 [1.8, 2.1]。第一个间隔的共享是 0.85 * (1.3-1) / (1.3-0.5) ,第二个间隔的共享是 1.6 * (2-1.8) / (2.1 - 1.8) 。等于1.3854 GB
    • @RomaKarageorgievich 1.6 * (2-1.8) / (2.1 - 1.8) == 1.06666 而不是 1,3854,除非我错过了什么?
    • 当然,但是句点 [1, 2] 还包括来自 [0.5, 1.3] 的份额。你想念它0.85 * (1.3-1) / (1.3-0.5)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-14
    • 2020-07-06
    • 2017-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-31
    相关资源
    最近更新 更多