R 对于每一行,查找最接近指定值的列
我有一个数据集,它有一个ID变量和数千列平均值。下面是一个可复制的示例。对于每个ID,我想选择包含最接近0.50的值的列名。如果存在平局,请选择最低值。有没有一种有效的方法可以更好地使用dplyr或data.table来实现这一点R 对于每一行,查找最接近指定值的列,r,dplyr,data.table,R,Dplyr,Data.table,我有一个数据集,它有一个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 X
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
我已将示例代码简化为较小的子集,以便在处理代码时节省处理器:
data.frame(
ID = df[1:5,1],
T = apply(df[1:5, 2:5],1, function(x) colnames(df)[which.min(abs(x - 0.5))]),
P = apply(df[1:5, 2:5],1, function(x) x[which.min(abs(x - 0.5))])
)
我想这就是你想要的。因为你的播放数据会自动重复,我会检查一些其他更随机的数据。是的,它使用它找到的第一个X变量,这就是我假设你所说的最小值 图书馆弹琴 设定2020年种子 df% summarseid=ID, col_index=哪个.minabsc_穿过x1:X2000-0.5+1, whichcolumn=colnames.[col_index], value=nthc_穿过x1:X2000,其中.minabsc_穿过x1:X2000-.5, .groups=行 后果 >一个tibble:1000x4 >顺时针: >列值所在的ID列索引 > >1 ID1 1925 X1924 0.501 >2 ID2 1441 X1440 0.499 >3 ID3 907 X906 0.500 >4 ID4 181 X180 0.503 >5 ID5 1758 X1757 0.498 >6 ID6 1569 X1568 0.500 >7 ID7 566 X565 0.501 >8 ID8 1448 X1447 0.502 >9 ID9 1345 X1344 0.500 >10 ID10 1019 X1018 0.501 >…还有990行
基本R解决方案,在出现平局时应始终选择较低的值:
num_cols_idx <- which(sapply(df, is.numeric))
min_vec <- sapply(split(df, rownames(df)), function(x) {
sorted_named_vec <- sort(unlist(x[num_cols_idx]))
names(sorted_named_vec)[which.min(abs(sorted_named_vec - 0.5))]
},
simplify = TRUE)
这里有一种不同的方法,它使用melt将数据集从宽格式重塑为长格式 现在,选择较低的值,以防出现领带。这可以通过订购来实现:
long[order(ID, value), .SD[which.min(abs(value - target))], by = ID]
请注意第1000行中的差异
通过链接data.table表达式,语句可以写成一行:
melt(setDT(df), "ID")[order(ID, value), .SD[which.min(abs(value - target))], by = ID]
还请注意,示例数据集已被修改
set.seed用于确保生成的随机数是可复制的。
通过使用sprintfID%04i,1:1000代替粘贴,ID具有固定长度。这有助于保持一致的排序顺序。
随机数四舍五入为3位数,以使其更有可能遇到平局。
如果列值之间存在关联,则会选择较低的值?min。该值会盲目地选择它看到的第一个min,因此无论哪个min最靠近向量头。欺骗它的唯一方法是首先将列从最低到最高排序相关:。首先抓取与0.5偏差最小的列,ci=max.col-absd[,-1]-0.5。然后data.frameid=d[,1],nm=namesd[,-1][ci],val=d[,-1][cbindseq_lennrowd,ci]请使用set.seed使随机数可复制。谢谢。不同的链接,可以说更可读:setDFdf;df[,melt.SD,ID][orderID,value,.SD[which.minabsvalue-target],by=ID]@sindri_baldur,您可以删除;链中的df:setDTdf[,melt.SD,ID][orderID,value,.SD[which.minabsvalue-target],by=ID],但这比meltsetdf,ID[orderID,value,.SD[which.minabsvalue-target],by=ID]稍微慢一点。我在c_函数中遇到了问题。我不知道为什么,但R找不到它。它是dplyr的一部分吗?
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
melt(setDT(df), "ID")[order(ID, value), .SD[which.min(abs(value - target))], by = ID]