Ruby 对数组进行量化,以便量化值的子集仍然是一致量化的

Ruby 对数组进行量化,以便量化值的子集仍然是一致量化的,ruby,rounding,quantization,Ruby,Rounding,Quantization,给定一个ints数组,我想对每个值进行量化,使量化值之和为100。每个量化值也应该是一个整数。当整个数组被量化时,这是可行的,但是当量化值的子集被加起来时,它不会相对于其余的值保持量化 例如,值44、40、7、2、0、0被量化为47、43、8、2、0、0(其和为100)。如果取最后4个量化值,则总和为53,与第一个值一致(即47+53=100) 但是对于值78、7、7、1、0、0,最后4个量化值(8、8、1、0、0)的和是17。第一个量化值是84,当与17相加时不等于100。显然,这是因为四舍五

给定一个
int
s数组,我想对每个值进行量化,使量化值之和为100。每个量化值也应该是一个整数。当整个数组被量化时,这是可行的,但是当量化值的子集被加起来时,它不会相对于其余的值保持量化

例如,值44、40、7、2、0、0被量化为47、43、8、2、0、0(其和为100)。如果取最后4个量化值,则总和为53,与第一个值一致(即47+53=100)

但是对于值78、7、7、1、0、0,最后4个量化值(8、8、1、0、0)的和是17。第一个量化值是84,当与17相加时不等于100。显然,这是因为四舍五入。是否有办法调整舍入,使子集保持一致

以下是Ruby代码:

class Quantize
  def initialize(array)
    @array = array.map { |a| a.to_i }
  end

  def values
    @array.map { |a| quantize(a) }
  end

  def sub_total(i, j)
    @array[i..j].map { |a| quantize(a) }.reduce(:+)
  end

  private

  def quantize(val)
    (val * 100.0 / total).round(0)
  end

  def total
    @array.reduce(:+)
  end
end
以及(未通过的)测试:


如关于该问题的评论中所述,量化例程没有正确执行:第二个示例
[78,7,7,1,0,0]
被量化为
[84,8,8,1,0,0]
——这增加了101而不是100

以下是一种能够产生正确结果的方法:

def quantize(array, value)
  quantized = array.map(&:to_i)
  total = array.reduce(:+)
  remainder = value - total

  index = 0

  if remainder > 0
    while remainder > 0 
      quantized[index] += 1
      remainder -= 1
      index = (index + 1) % quantized.length
    end
  else
    while remainder < 0 
      quantized[index] -= 1
      remainder += 1
      index = (index + 1) % quantized.length
    end
  end

  quantized
end
def量化(数组,值)
quantized=array.map(&:to_i)
总计=数组。减少(:+)
余数=值-总计
索引=0
如果余数大于0
而余数>0
量化[索引]+=1
余数-=1
索引=(索引+1)%quantized.length
结束
其他的
余数<0
量化[索引]-=1
余数+=1
索引=(索引+1)%quantized.length
结束
结束
量化
结束

正如问题中所述,这解决了您的问题。麻烦的结果变成
[80,8,8,2,1,1]
,这将增加到100并保持您描述的子集关系。当然,解决方案的性能会更高,但它的优点是可以工作并且非常容易理解。

运行代码时,第二个示例的量化(如您在测试用例中所说)是[84,8,8,1,0,0]。这会增加101,而不是你想要的100。此外,最后5位数字的总和是17,而不是你在问题中所说的15。因此,有一个比你在问题中描述的更深的问题。也就是说,舍入是有缺陷的。这与子集无关。@M.AnthonyAiello你说得对。差异是由于编辑不好造成的。“我会解决它的。”ReedGLaw-编辑有帮助-但问题仍然比子集更基本。第二个例子加起来不是100,而是101。因此,1)你的算法一开始并没有达到你想要的效果,更不用说子集了;2)您的测试用例不会暴露错误。对于后者,我建议对量化值求和以确保它们等于100,而不是指定量化必须是什么。@M.AnthonyAiello再一次你是对的。看看第二个例子(83.87097,7.52688,7.52688,1.07527,0.0,0.0)的未经修正的结果,我发现测试应该期望什么并不明显。7.52688值中的一个是否应向上舍入到8,另一个应向下舍入到7?我应该更详细地描述实际问题。原始值代表临床试验中的患者。该数组的六个元素各代表一个不良事件等级(0表示无不良事件,5表示死亡)。这些值应以百分比的形式显示在表格中,以便它们看起来一致。(从上一条评论继续)。。。因此,在第二个例子中,78名患者为0级(无不良事件),7名为1级,7名为2级,1名为3级。共有93名(78+7+7+1)患者。对于最终表格,显示的是百分比,而不是患者数量。百分比应保持一致,以便加起来等于100。读取代码时,似乎会在数组中循环对每个值加1或减1,直到总数等于
。这个解决方案的问题是,如果您阅读了我在问题注释中对问题域的描述,您会看到似乎有1%的患者死亡(
量化[4]
),而实际上没有(
数组[4]
)死亡。另外,
量化[0]
为80,但这与实际的百分比值83.87097相差甚远。如果某些值必须伪造,我宁愿它是7.52688(
量化[1..2]
)。这就意味着一个四舍五入到8,另一个四舍五入到7.5。但问题的原始参数没有规定这些限制。我甚至不知道你需要缩放,直到你后来的评论。正如最初所说,这确实解决了问题。我认为这可以进行调整,使其发挥作用。我要做的就是跳过等于0的数组元素。我来试试。我应该一直用“缩放”这个词。我的错误是不知道该怎么称呼这个问题。量化用于将连续值集(如信号)约束到相对较小的离散集。我只想用不同的比例来表示一组数字。
def quantize(array, value)
  quantized = array.map(&:to_i)
  total = array.reduce(:+)
  remainder = value - total

  index = 0

  if remainder > 0
    while remainder > 0 
      quantized[index] += 1
      remainder -= 1
      index = (index + 1) % quantized.length
    end
  else
    while remainder < 0 
      quantized[index] -= 1
      remainder += 1
      index = (index + 1) % quantized.length
    end
  end

  quantized
end