首页 > 解决方案 > 将变量分成几部分并将每个部分的总和相加

问题描述

我的数据集有 200 万个观察值。我想根据变量“rv”的值将其分成 200 个类别。例如,假设我有 0-1000、1000-2000、2000-3000、3000-4000、4000-5000 的类别,我想像这样拆分一个值为 4500 的观察:前 4 个类别中的每个类别都有 1000,并且最后一类500。我有以下代码,它可以工作但很慢:

# create random data set
import pandas as pd
import numpy as np
data = np.random.randint(0, 5000, size=2000)
df = pd.DataFrame({'rv': data})

#%% slice
sizes = [0, 1000, 2000, 3000, 4000, 5000]
size_names = ['{:.0f} to {:.0f}'.format(lower, upper) for lower, upper in zip(sizes[0:-1], sizes[1:])]

for lower, upper, name in zip(sizes[0:-1], sizes[1:], size_names):
    df[name] = df['rv'].apply(lambda x: max(0, (min(x, upper) - lower)))

# summary table
df_slice = df[size_names].sum()

有没有更好的方法来做到这一点,其中更好意味着更快?有 200 万个观察和 200 个类别,这需要相当长的时间(不知道我在代码完成之前停止了多长时间)。

标签: pythonpandas

解决方案


我编写了一个预先对数据进行排序的算法,它将数据从 O(n*m) 循环(在数据和类别上)带到 O(n) 循环(就在数据上,尽管有一个 O(n log n) 排序时间)。通过对它进行排序,您已经知道自己在哪个 bin 中,只需处理该特定 bin 的总和,然后将总和应用于该 bin 以及每个 bin 下的所有 bin 一次。200 个类别的 200 万个数据点大约需要 1.2 秒。希望能帮助到你:

from time import time
from random import randint

data = [randint(0, 4999) for i in range(2000000)]
sizes = range(0, 5001, 25)
bound_pairs = [[sizes[i], sizes[i + 1]] for i in range(len(sizes) - 1)]
results = [0 for i in range(len(sizes) - 1)]

data.sort()

curr_bin = 0
curr_bin_count = 0
curr_bin_sum = 0
for d in data:
    if d >= bound_pairs[curr_bin][1]:
        results[curr_bin] += curr_bin_sum
        for i in range(curr_bin):
            results[i] += curr_bin_count * (bound_pairs[i][1] - bound_pairs[i][0])
        curr_bin_count = 0
        curr_bin_sum = 0

        while d >= bound_pairs[curr_bin][1]:
            curr_bin += 1

    curr_bin_count += 1
    curr_bin_sum += d - bound_pairs[curr_bin][0]

results[curr_bin] += curr_bin_sum
for i in range(curr_bin):
    results[i] += curr_bin_count * (bound_pairs[i][1] - bound_pairs[i][0])

编辑:这里可能存在一些问题,具体取决于您希望上限或下限是包容性的还是独占性的。我把细节留给你。


推荐阅读