我需要使用给定的比率[0.55, 0.45]细分给定数量的项目(假设10个),这里的结果应该是6:4或5:5。通常的方法[0.55*10, 0.45*10]将导致[6, 5](11,而不是10)。另一个例子:使用比率除以7:[0.36, 0.44, 0.07, 0.07, 0.03, 0.03],其理想地应当产生类似于[3, 3, 1, 0, 0, 0]或[3, 3, 0, 1, 0, 0]的值。解决这个问题的好办法是什么?
[0.55, 0.45]
[0.55*10, 0.45*10]
[6, 5]
[0.36, 0.44, 0.07, 0.07, 0.03, 0.03]
[3, 3, 1, 0, 0, 0]
[3, 3, 0, 1, 0, 0]
l2osamch1#
下面是我对这个问题的尝试:)最困难的部分是反转排序操作并将其与结果匹配...如果您不需要保持原始的比率顺序,那么您可以删除最后一个函数的一部分。
def scale_ratio(ratios: list) -> list: sum_ = sum(ratios) return [x/sum_ for x in ratios] def ratio_breakdown_recursive(x: int, ratios: list) -> list: top_ratio = ratios[0] part = round(x*top_ratio) if x <= part: return [x] x -= part return [part] + ratio_breakdown_recursive(x, scale_ratio(ratios[1:])) def ratio_breakdown(x: int, ratios: list) -> list: sorted_ratio = sorted(ratios, reverse=True) assert(round(sum(ratios)) == 1) sorted_result = ratio_breakdown_recursive(x, sorted_ratio) assert(sum(sorted_result) == x) # Now, we have to reverse the sorting and add missing zeros sorted_result += [0]*(len(ratios)-len(sorted_result)) numbered_ratios = [(r, i) for i, r in enumerate(ratios)] sorted_numbered_ratios = sorted(numbered_ratios, reverse=True) combined = zip(sorted_numbered_ratios, sorted_result) combined_unsorted = sorted(combined, key=lambda x: x[0][1]) unsorted_results = [x[1] for x in combined_unsorted] return unsorted_results
结果:
ratio_breakdown(7, [0.36, 0.44, 0.07, 0.07, 0.03, 0.03]) [3, 3, 1, 0, 0, 0] ratio_breakdown(10, [0.55, 0.45]) [6, 4] ratio_breakdown(16, [0.16, 0.47, 0.13, 0.24]) [2, 8, 2, 4]
编辑:这是Python3。
r3i60tvu2#
我建议你用另一个数组,我是Python的初学者。下面是你的例子的代码(我相信你可以简单地修改它):
a = [0.36, 0.44, 0.07, 0.07, 0.03, 0.03] numberItem = 7 remainder = numberItem b = [0,0,0,0,0,0] for i in range(0,6): b[i] = round(a[i]*numberItem) if (b[i] > remainder) or (b[i] == 0): b[i] = remainder remainder = 0 else: remainder = remainder - b[i] print(b[i])
在这个范围内,你不能有比指定的更多的项。如果比率数组从大到小排序会更好。
1qczuiv03#
下面是@maciek算法的非递归NumPy实现:
import numpy as np def split_integer_into_parts(x: int, ratios: list) -> np.ndarray: ratios = np.array(ratios, dtype=float) assert x >= 0 assert (ratios >= 0).all() assert ratios.sum() > 0 # sort ratios sort_idx = np.argsort(-ratios) ratios = ratios[sort_idx] # compute fractions of the remainders ratios_cumsum = np.cumsum(ratios[::-1])[::-1] fracs = np.divide(ratios, ratios_cumsum, out=np.ones_like(ratios), where=(ratios_cumsum != 0)) # split integer into parts remainder = x parts = np.zeros_like(fracs, dtype=int) for i, frac in enumerate(fracs): parts[i] = round(remainder * frac) remainder -= parts[i] assert parts.sum() == x # unsort parts parts = parts[np.argsort(sort_idx)] return parts
o0lyfsai4#
我一直在寻找这个问题/答案,但是我在R中工作,所以我用R为任何通过这种方式的人重写了@Maciek的答案,我尽可能地使它接近Python中的原始答案。
library(dplyr) scale_ratio <- function(ratios){ sum_ <- sum(ratios) return(ratios/sum_) } ratio_breakdown_recursive <- function(x, ratios){ top_ratio <- ratios[1] part <- round(x*top_ratio) if (x <= part){ return(x) } x <- (x - part) c(part, ratio_breakdown_recursive(x, scale_ratio(ratios[2:length(ratios)]))) } ratio_breakdown <- function(x, ratios){ x <- x[1] sorted_ratio = sort(ratios, decreasing = TRUE) stopifnot(round(sum(ratios)) == 1) sorted_result = ratio_breakdown_recursive(x, sorted_ratio) stopifnot(sum(sorted_result) == x) # Now, we have to reverse the sorting and add missing zeros sorted_result <- append(sorted_result, rep(0, length(ratios) - length(sorted_result))) numbered_ratios <- data.frame(ratios, seq_along(ratios)) sorted_numbered_ratios <- arrange(numbered_ratios, desc(ratios)) combined <- cbind(sorted_numbered_ratios, sorted_result) combined_unsorted <- arrange(combined, seq_along.ratios.) unsorted_results <- combined_unsorted[,3] return(unsorted_results) }
> ratio_breakdown(7, c(0.36, 0.44,0.07,0.07,0.03,0.03)) [1] 3 3 0 1 0 0 > ratio_breakdown(10, c(0.55,0.45)) [1] 6 4 > ratio_breakdown(16, c(0.16,0.47,0.13,0.24)) [1] 2 8 2 4
我意识到第一个答案返回的顺序与@Maciek的答案不同,但就我的目的而言,这是有效的,如果有人能改进我的R代码,请自便--我很乐意学习。
4条答案
按热度按时间l2osamch1#
下面是我对这个问题的尝试:)最困难的部分是反转排序操作并将其与结果匹配...如果您不需要保持原始的比率顺序,那么您可以删除最后一个函数的一部分。
结果:
编辑:这是Python3。
r3i60tvu2#
我建议你用另一个数组,我是Python的初学者。
下面是你的例子的代码(我相信你可以简单地修改它):
在这个范围内,你不能有比指定的更多的项。如果比率数组从大到小排序会更好。
1qczuiv03#
下面是@maciek算法的非递归NumPy实现:
o0lyfsai4#
用R书写的接受答案
我一直在寻找这个问题/答案,但是我在R中工作,所以我用R为任何通过这种方式的人重写了@Maciek的答案,我尽可能地使它接近Python中的原始答案。
我意识到第一个答案返回的顺序与@Maciek的答案不同,但就我的目的而言,这是有效的,如果有人能改进我的R代码,请自便--我很乐意学习。