R 对于每一行,查找最接近指定值的列

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

我有一个数据集,它有一个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

我已将示例代码简化为较小的子集,以便在处理代码时节省处理器:

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]