【问题标题】:Pythonic way of binning data without pandas/numpy没有 pandas/numpy 的 Pythonic 分箱数据方式
【发布时间】:2020-11-24 22:15:20
【问题描述】:

我正在寻找一种方法,将包含数百个条目的数据集分箱到 20 个箱中。但是没有使用像 pandas (cut) 和 numpy (digitize) 这样的大模块。 谁能想到比 18 个 elif 更好的解决方案?

【问题讨论】:

    标签: python-3.x data-science binning


    【解决方案1】:

    您需要做的就是弄清楚每个元素在哪个 bin 中。考虑到 bin 的大小(如果它们是统一的),这相当简单。从您的阵列中,您可以找到minvalmaxval。然后,binwidth = (maxval - minval) / nbins。对于数组中的元素elem,以及已知的最小值minval 和bin 宽度binwidth,该元素将落在bin 编号int((elem - minval) / binwidth) 中。这留下了elem == maxval 的边缘情况。在这种情况下,bin 编号等于 nbinsnbins + 1th bin,因为 python 是从零开始的),所以我们必须减少这种情况下的 bin 编号。

    所以我们可以写一个这样的函数:

    import random
    
    def splitIntoBins(arr, nbins, minval=None, maxval=None):
        minval = min(arr) if minval is None else minval # Select minval if specified, otherwise min of data
        maxval = max(arr) if maxval is None else maxval # Same for maxval
        
        binwidth = (maxval - minval) / nbins # Bin width
        allbins = [[] for _ in range(nbins)] # Pre-make a list-of-lists to hold values
    
        for elem in arr:
            binnum = int((elem - minval) // binwidth) # Find which bin this element belongs in
            binindex = min(nbins-1, binnum) # To handle the case of elem == maxval
            allbins[binindex].append(elem) # Add this element to the bin
        return allbins
    
    # Make 1000 random numbers between 0 and 1
    x = [random.random() for _ in range(1000)]
    
    # split into 10 bins from 0 to 1, i.e. a bin every 0.1
    b = splitIntoBins(x, 10, 0, 1)
    
    # Get min, max, count for each bin
    counts = [(min(v), max(v), len(v)) for v in b]
    print(counts)
    

    这给了

    [(0.00017731201786974626, 0.09983758434153, 101),
     (0.10111204267013452, 0.19959594179848794, 97),
     (0.20089309189822557, 0.2990120768922335, 100),
     (0.3013915797055913, 0.39922131591077614, 90),
     (0.4009006835799309, 0.49969892298935836, 83),
     (0.501675740585966, 0.5999729295882031, 119),
     (0.6010149249108184, 0.7000366124696699, 120),
     (0.7008002068562794, 0.7970568220766774, 91),
     (0.8018697850229161, 0.8990963218226316, 99),
     (0.9000732426223624, 0.9967964437788829, 100)]
    

    这看起来和我们预期的一样。

    对于不均匀的 bin,不再是算术计算。在这种情况下,元素 elem 位于下限小于 elem 且上限大于 elem 的 bin 中。

    def splitIntoBins2(arr, bins):
        binends = bins[1:]
        binstarts = bins[:-1]
        allbins = [[] for _ in binends] # Pre-make a list-of-lists to hold values
    
        for elem in arr:
            for i, (lower_bound, upper_bound) in enumerate(zip(binstarts, binends)):
                if upper_bound >= elem and lower_bound <= elem:
                    allbins[i].append(elem) # Add this element to the bin
                    break
        return allbins
    

    【讨论】:

    • minval = minval or min(arr) 是一个错误,如果 minval0 并且 min(arr) 不是 0。检查minval is None 总是更好(甚至稍微快一点)。您可以使用三元表达式或仅使用 if-else 语句。
    • 好收获@juanpa.arrivillaga
    猜你喜欢
    • 2019-05-21
    • 1970-01-01
    • 2017-02-25
    • 1970-01-01
    • 2018-02-09
    • 1970-01-01
    • 2020-12-02
    • 2020-09-10
    相关资源
    最近更新 更多