我有170行带有小数点的数字,需要四舍五入为整数。但是,行总数必须等于我指定的数字。
作为一个非常基本的说明,假设我有一个矩阵(1x4),其中包含单元格内容(1.2、3.4、7.7、5.3)。但是,假设这些数字代表的是个人,因此我需要将它们四舍五入为整数,以使群体总数等于18个人的总数。如果我简单地四舍五入矩阵内容,得出的结果是(1、3、8、5),那么我的总数为17,我需要等于18(请参见下面的R命令)。
将数字四舍五入后,我需要R然后选择最接近四舍五入的下一个数字(即3.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是四舍五入后需要累加的总数。
简而言之,我正在寻找一个对整个数据集(而不是单个行)有用的函数。理想情况下,我可以调用要四舍五入的数字的列,也可以调用需要四舍五入的数字等于的总数的列。
更新了信息
作为更说明性的示例。假设我的人口中有两个种族。
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,但是我需要对每个位置行中的内容进行四舍五入,以使我的place(1-4)总计为4.0、7.0、8.0和7.0。因此,对于place1来说,我需要将内容四舍五入,以使1.2变为2.0,而2.1变为2.0。等于4.0,我的注册选民人数。对于place2,总数已经为7,所以我们还可以。对于place3,7.7将变为7.0,而0.8将变为1,总共给我8。最后,对于place4,我需要将5.3舍入为5,将1.4舍入为2.0,总共给我7。我想要的是:
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
的两列中的1-1映射以及dat
中的每个对应值,就在每一行上执行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
/mapply
或Vectorize
Round
来想出一些更聪明的方法来避免这些循环,但是看来您的数据似乎不是很大。关于R:四舍五入每一行中的内容,以使行总数等于我指定的数字,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25829504/