2017-01-05 12 views
3

У меня есть кадр данных с разными идентификаторами, и я хочу создать подгруппу, в которой: для каждого идентификатора я получаю только одну строку с ближайшим значением до 0,5 в переменной Y .Возвращаемые строки, устанавливающие «ближайшее значение» в R

Это мой кадр данных:

df <- data.frame(ID=c("DB1", "BD1", "DB2", "DB2", "DB3", "DB3", "DB4", "DB4", "DB4"), X=c(0.04, 0.10, 0.10, 0.20, 0.02, 0.30, 0.01, 0.20, 0.30), Y=c(0.34, 0.49, 0.51, 0.53, 0.48, 0.49, 0.49, 0.50, 1.0) )

Это то, что я хочу, чтобы получить

ID X Y DB1 0.10 0.49 DB2 0.10 0.51 DB3 0.30 0.49 DB4 0.20 0.50

Я знаю, что могу добавить фильтр с ddply, используя что-то вроде этого

ddply(df, .(ID), function(z) { z[z$Y == 0.50, ][1, ] })
и это будет работать хорошо, если там были всегда 0,50 значение Y, которое не так.

Как изменить значение == для «ближайшего к» 0.5, или есть ли другая функция, которую я мог бы использовать вместо этого?

Спасибо заранее!

+0

Я думаю, что у вас есть опечатка в создании данных - во втором идентификаторе строки у вас есть BD1, где я думаю, что вы имеете в виду 'DB1'. – Gregor

ответ

7

Вам нужно рассчитать разницу от 0.5, а затем сохранить самый маленький. Один из способов сделать это было бы так, как:

ddply(df, .(ID), function(z) { 
    z[abs(z$Y - 0.50) == min(abs(z$Y - 0.50)), ] 
}) 

Обратите внимание, что путь я закодировал выше, опуская ваш [1, ], если две строки точно связаны и будут сохранены.

Это должно быть хорошо, поскольку мы делаем точный расчет по обе стороны от ==, но я часто беспокоюсь о проблемах с числовой точностью, поэтому вместо этого мы могли бы использовать which.min. Обратите внимание, что which.min вернет первый минимум в случае галстука.

ddply(df, .(ID), function(z) { 
    z[which.min(abs(z$Y - 0.50)), ] 
}) 

Другим надежным способом сделать это было бы заказать кадр данных по разности от 0,5 и сохранить первую строку на идентификатор. На этом этапе я перейду на dplyr, хотя, конечно, вы можете использовать dplyr или plyr::ddply для любого из этих методов.

library(dplyr) 
df %>% group_by(ID) %>% 
    arrange(abs(Y - 0.5)) %>% 
    slice(1) 

Я не уверен, как arrange обрабатывает галстуки. Для получения дополнительных методов см. Get rows with minimum of variable, but only first row if multiple minima, и всегда используйте abs(Y - 0.5) как переменную, которую вы минимизируете.

+0

Base R translation - 'df [ave (df $ Y, df $ ID, FUN = function (x) seq_along (x) == which.min (abs (x-0.5))) == 1,]' – thelatemail

+0

Или 'df%>% group_by (ID)%>% filter (row_number() == which.min (abs (Y-0.5)))' – HubertL

+0

@HubertL в этой точке просто 'df%>% group_by (ID)%> % slice (which.min (abs (Y - 0.5))) ' – Gregor