TLDR: 当有超过3M个bin /类别时,如何将pandas.Series
中的记录分配给pd.category
?当前正在尝试pd.cut
,但这很棘手。
我有一些数据经过直方图,然后使用peakutils
查找直方图的峰。然后,我或多或少地在峰之间分配数据。我有一个快速的过程来执行此操作,结果看起来大致如下所示。
说我在bin位置[5, 9, 16]
上有一个峰值。我想将位于容器[0, 1, 2, 4, 5, 6, 7]
中的所有数据分配给类0
。 [8, 9, 10, 11, 12]
中的数据归为1
类,而[13, 14, 15, 16, ...]
中的数据归为2
类。
回收箱的总数很大(> 3M)。可以,因为我的寻峰工作很快。 问题是,当我尝试使用pd.cut
将垃圾箱映射回我的原始数据时,事情变得棘手。
通常情况下,我的代码如下所示
# 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
范围内的bin总数。它能够在可接受的时间内完成此操作。我认为问题出在cat.codes
的垃圾箱中。他们不再排队与我的current_peak
。
在撰写本文时,我只是想了些什么,但必须尝试一下,我仍然会问这个问题,以防比我聪明的人有更好的主意。也许我可以用bdata
或类似的值来索引edges
边。
无论如何,我希望这是清楚的。
TIA
答案 0 :(得分:0)
大量研究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
希望这可以帮助其他有类似问题的人。如果您有任何问题,我会尽力回答。