我有一个数据集,其中包含一个 ID 变量和数千列平均值。下面是一个可重现的示例。对于每个 ID,我想选择包含最接近 0.50 的值的列名称。如果存在平局,则选择最低值。有没有有效的方法来做到这一点(最好使用 dplyr 或 data.table)?
df = data.frame(ID = paste("ID", 1:1000, sep = ""),
matrix(rnorm(20000), nrow=10))
> df[1:5, 1:5]
ID X1 X2 X3 X4
1 ID1 -0.5532944 -1.20671805 0.75142048 0.56022595
2 ID2 -1.0083010 -0.01534611 1.53546691 -0.08762588
3 ID3 -0.1606776 -0.96947669 -0.38631278 -1.15647134
4 ID4 -0.5957471 -0.20918120 -0.05246698 -0.84235789
5 ID5 0.1569595 -0.62460245 -0.39454014 0.91089249
我的目标是拥有一个包含 ID 变量和列名的数据框,其中包含最接近 0.5 的值以及该值。
ID T P
1 ID1 X10 0.5671
2 ID2 X100 0.4999
3 ID3 X34 0.5877
4 ID4 X21 0.5055
5 ID5 X15 0.4987
最佳答案
这是一种不同的方法,它使用 melt()
将数据集从宽格式 reshape 为长格式。
# create sample data: ID has constant length, values are rounded to 3 digits
set.seed(2020)
df = data.frame(ID = sprintf("ID%04i", 1:1000),
matrix(round(rnorm(20000), 3), nrow=10))
target <- 0.5
library(data.table)
long <- melt(setDT(df), "ID")
long[, .SD[which.min(abs(value - target))], by = ID]
ID variable value 1: ID0001 X1924 0.501 2: ID0002 X1440 0.499 3: ID0003 X906 0.500 4: ID0004 X180 0.503 5: ID0005 X1757 0.498 --- 996: ID0996 X1568 0.500 997: ID0997 X565 0.501 998: ID0998 X613 0.502 999: ID0999 X1344 0.500 1000: ID1000 X1018 0.501
现在,OP has requested在平局的情况下选择较低的值。这可以通过订购来实现:
long[order(ID, value), .SD[which.min(abs(value - target))], by = ID]
ID variable value 1: ID0001 X1924 0.501 2: ID0002 X1440 0.499 3: ID0003 X906 0.500 4: ID0004 X180 0.503 5: ID0005 X1757 0.498 --- 996: ID0996 X1568 0.500 997: ID0997 X565 0.501 998: ID0998 X613 0.502 999: ID0999 X1344 0.500 1000: ID1000 X1971 0.499
注意第 1000 行中的差异。
通过链接data.table
表达式,该语句可以写成“one-liner”:
melt(setDT(df), "ID")[order(ID, value), .SD[which.min(abs(value - target))], by = ID]
另请注意,示例数据集已被修改
set.seed()
用于确保生成的随机数是可重现的。- 通过使用
sprintf("ID%04i", 1:1000)
而不是paste()
,ID
具有固定长度。这有助于保持一致的排序顺序。 - 随机数四舍五入为 3 位数字,以提高出现平局的可能性。
关于r - 对于每一行,找到最接近指定值的列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62394530/