【问题标题】:How to use pd.cut with LARGE number of Bins?如何将 pd.cut 与大量垃圾箱一起使用?
【发布时间】:2019-12-11 22:10:44
【问题描述】:

TLDR:当有>3M 个分类/类别时,如何将pandas.Series 中的记录分配给pd.category?目前正在尝试pd.cut,但这很棘手。

我有一些数据通过直方图运行,然后使用peakutils 找到直方图的峰值。然后我在峰值之间或多或少地拆分数据。我有一个快速的过程来执行此操作,结果看起来或多或少类似于以下内容。

假设我在 bin 位置 [5, 9, 16] 有一个峰值。我想将位于 bin [0, 1, 2, 4, 5, 6, 7] 中的所有数据分配给类 0[8, 9, 10, 11, 12] 中的数据到1 类,[13, 14, 15, 16, ...] 中的数据到2 类。

返回的 bin 总数很多 (> 3M)。没关系,因为我的峰值查找速度很快。 问题是,当我尝试使用 pd.cut 将我的 bin 映射回我的原始数据时,事情变得难以处理。

在正常情况下,我的代码如下所示

# data is a pd.Series with about 600k records in it
hist, edges = np.histogram(data, bins='fd')
peakIndex = peakutils.indexes(hist, thres=0.01, min_dist=10)
peaks_counts = np.zeros(len(enges)-1)

# takes forever when length of `edges` >= 3M
bdata = pd.cut(data, bins=edges, include_lowest=True) # <-- This is what needs to be sped up
bdata["codes"] = bdata[data.name].cat.codes
midpoints = peakIndex[:-1\ + np.ceil(np.diff(peakIndex)/2)
midpoints = np.insert(midpoints, 0, 0)
midpoints = np.append(midpoints, len(edges))

# merge the non point bins with the bins that are peaks as described above. 
for ix in range(len(midpoints)):
    _from = midpoints[ix].astype(int)
    _to = midpoints[ix].astype(int)
    current_peak = np.arange(_from, _to)
    bdata["codes"] = bdata["codes"].replace(current_peak, [edges[ix] for e in current_peak])

直方图hist 的计数有很多0 计数。所以我想我可以很聪明,删除计数为0 的垃圾箱。这样做减少了pd.cut 循环到37k 范围内的垃圾箱总数。它能够在可接受的时间内做到这一点。我认为问题出现在垃圾箱的cat.codes 上。他们不再与我的current_peak 排队。

在我写这篇文章时,我只是想到了一些东西,但必须尝试一下,我仍然会问这个问题,以防比我更聪明的人有更好的想法。也许我可以用edges 或类似的值索引bdata 边缘。

我希望这很清楚..

TIA

【问题讨论】:

    标签: python pandas numpy


    【解决方案1】:

    在对 Pandas 源代码进行大量挖掘之后,我发现pd.cut 的缓慢部分不是数据到 bin 的映射,而是分类数据类型的创建。我所做的或多或少如下:

    bins = pd.core.algorithms.unique(bins) # probably not really needed but hey why take the chance
    
    # this is what maps data to bins and its pretty quick
    ids = pd.core.dtypes.common.ensure_int64(bins.searchsorted(data, side="left"))
    ids[data == bins[0]] = 1 # this is the include lowest feature of `pd.cut`
    
    labels = pd.core.reshape.tile._format_labels(bins, 3, right=True, include_lowest=True)
    labels = pd.Categorical(labels, categories=labels, ordered=True)
    
    bdata = pd.core.algorithms.take_nd(labels, ids - 1)
    bdata = pd.DataFrame(bdata)
    bdata["codes"] = ids
    

    希望这可以帮助遇到类似问题的其他人。如果您有任何问题,我会尽力回答。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-08
      • 1970-01-01
      • 1970-01-01
      • 2012-03-03
      • 1970-01-01
      • 1970-01-01
      • 2021-04-20
      相关资源
      最近更新 更多