R:对每行内的内容进行四舍五入,使行总计等于我指定的数字

标签 r function rounding

我有 170 行带小数的数字,需要四舍五入为整数。但是,行总数必须等于我指定的数字。

作为一个非常基本的说明,假设我有一个矩阵 (1x4),其单元格内容为 (1.2、3.4、7.7、5.3)。但假设这些数字代表个体,因此我需要将它们四舍五入为整数,这样群体人口等于 18 个人的总人口。如果我简单地对矩阵内容进行舍入,得到 (1, 3, 8, 5),我的总人口是 17,我需要它等于 18(请参阅下面的 R 命令)。

m <- c(1.2, 3.4, 7.7, 5.3)

m.2 <- round(m)

m.2 [1] 1 3 8 5

sum(m.2) [1] 17

数字四舍五入后,我需要 R 选择下一个最接近四舍五入的数字(即 3.4)并将其四舍五入为 4 而不是 3。

这会给我一个矩阵 (1, 4, 8, 5) = 18。

博士。 John Fox 帮助我用一个简单的递归函数来解决这个问题:

Round <- function(x, target){
 r.x <- round(x)
 diff.x <- round(x) - x
 if ((s <- sum(r.x)) == target) return(r.x)
 else if (s > target) {
     select <- seq(along=x)[diff.x > 0]
     which <- which.max(diff.x[select])
     x[select[which]] <- r.x[select[which]] - 1
     Round(x, target)
 }
 else{
     select <- seq(along=x)[diff.x < 0]
     which <- which.min(diff.x[select])
     x[select[which]] <- r.x[select[which]] + 1
     Round(x, target)
  }
 }

这对于单独的行非常有用。但我的数据集中有 170 行。因此,这意味着重复这样的过程(见下文)170 次:

paste(STATA[['b']], collapse=", ")

B <- c(46.8310012817383, 19.9720001220703, 265.837005615234, 95.0400009155273, 6.88700008392334, 190.768997192383, 22.7269992828369, 764.453002929688, 53.0299987792969, 333.329010009766, 55.0960006713867, 84.0210037231445, 28.2369995117188, 2207.27099609375, 86.7760009765625, 50045.46875, 103.304000854492, 413.217987060547, 4.13199996948242, 2.75500011444092, 183.88200378418, 65.4260025024414, 0.689000010490417, 2248.59204101562, 0, 1.37699997425079, 16.5289993286133, 4.13199996948242, 4.13199996948242, 2.75500011444092, 4.13199996948242, 1.37699997425079, 0, 39.9440002441406, 2.75500011444092, 28.2369995117188, 0, 0, 5.51000022888184, 0, 48.8969993591309, 17.9060001373291, 485.531005859375, 1.37699997425079, 59.9169998168945, 221.759994506836, 28.2369995117188, 4.13199996948242, 65.4260025024414, 11.0190000534058, 38.5670013427734, 3.44300007820129, 8.95300006866455, 2.75500011444092, 23.4160003662109, 4.13199996948242, 50.5750015258789, 11.7080001831055, 19.2830009460449, 48.8969993591309, 0, 13.7740001678467, 92.9739990234375)

varB <- (Round(B, 58701))

ROUND2012$varB <- varB

^在本例中,我在 Excel 中使用了数据集的转置,因为我发现与附加行相比,在 R 中将列附加到数据集更容易。但理想情况下,我不必这样做,行将是我的领土,列是群体身份人口数据。这里,“b”是我调用的列的名称,58701 是这些数字在四舍五入后需要相加的人口总数。

简而言之,我正在寻找一个对整个数据集而不是单个行有帮助的函数。理想情况下,我能够调用包含要舍入的数字的列,以及调用包含我需要舍入的数字等于的人口总数的列。

更新信息

作为一个更具说明性的示例。假设我的人口中有两个种族群体。

B

     race1 race2 total

place1  1.2  2.1  3.4

place2  3.4  3.6  7.0

place3  7.7  0.8  8.5

place4  5.3  1.4  6.7

我需要这些数字等于我的登记选民总数。总计为 3.4、7.0、8.5、6.7,但我需要对每个位置行中的内容进行四舍五入,以便我的位置 (1-4) 总计为 4.0、7.0、8.0 和 7.0。这意味着对于 place1,我需要对内容进行四舍五入,以便 1.2 变为 2.0,2.1 变为 2.0。我的登记选民人数等于 4.0。对于第二名,总数已经是 7,所以我们没问题。对于 place3,7.7 将变为 7.0,0.8 将变为 1,总共为 8。最后,对于 place4,我需要 5.3 舍入为 5,1.4 舍入为 2.0,总共为 7。我想要的是:

B

     race1 race2 total

place1  2.0  2.0  4.0

place2  3.0  4.0  7.0

place3  7.0  1.0  8.0

place4  5.0  2.0  7.0

目前,上面粘贴的舍入函数允许我一次调用一系列数字,并手动输入需要舍入的总数。但我正在寻找一个可以同时完成这一切的功能。我想将所有种族列称为四舍五入,并调用包含所有必要人口总数的列。 (注意:实际上,我在 excel 中对矩阵进行了转置,并将其重新导入到 R 中,因为作为一个相当新的 R 用户,我发现将新列附加到数据集比附加新行更容易。但是我绝对不需要执行该步骤,而且实际上也不想这样做。)

最佳答案

有几种方法可以做到这一点,但请采纳我上面的评论:

Round <- function(x, target) {
  r.x <- round(x)
  diff.x <- round(x) - x
  if ((s <- sum(r.x)) == target) {
    return(r.x)
  } else if (s > target) {
    select <- seq(along=x)[diff.x > 0]
    which <- which.max(diff.x[select])
    x[select[which]] <- r.x[select[which]] - 1
    Round(x, target)
  } else {
    select <- seq(along=x)[diff.x < 0]
    which <- which.min(diff.x[select])
    x[select[which]] <- r.x[select[which]] + 1
    Round(x, target)
  }
}

dat <- read.table(header = TRUE, row.names = paste0('place', 1:4),
                  text="race1 race2 total
                        1.2  2.1  3.4
                        3.4  3.6  7.0
                        7.7  0.8  8.5
                        5.3  1.4  6.7")

totals <- c(4.0, 7.0, 8.0, 7.0)

这两个示例只是执行 Round在每一行上使用 dat 的两列的 1-1 映射与 totals 中的每个对应值

lapply返回一个列表,因此要将输出转换回矩阵/数据帧,我们 rbind一切都回到了一起。

do.call(rbind, lapply(1:nrow(dat), function(x) Round(dat[x, -3], totals[x])))

#        race1 race2
# place1     2     2
# place2     3     4
# place3     7     1
# place4     5     2

apply的输出转换为你想要的,所以我们 t结果

dat[3] <- totals

t(apply(dat, 1, function(x) Round(x[1:2], x[3])))

#        race1 race2
# place1     2     2
# place2     3     4
# place3     7     1
# place4     5     2

或者,您可能可以使用Map想出更聪明的东西。/mapplyVectorize Round以避免这些循环,但您的数据似乎不是很大。

关于R:对每行内的内容进行四舍五入,使行总计等于我指定的数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25829504/

相关文章:

r - R中MAD函数和手动MAD计算的区别

C 使用函数计算阶乘

C++ - 需要左值作为赋值的左操作数

c# - Math.Round,保留小数位

R - 尽快初始化数据帧

r - 从一个函数中加载一个包

python - 如何正确舍入半 float ?

android - 在 EditText 中四舍五入小数

R Shiny 的数据表分页并将所有行显示为选项

由于错误的指针导致的 c 段错误