2017-02-02 2 views
0

Я пытаюсь использовать dplyr или DT, чтобы определить, если после первого вхождения значения любые последующие значения меньше заданного значения.Поиск любых значений, меньших, чем первое вхождение значения

Так что, если у меня есть кадр данных, как показано ниже,

df2 <- data.frame(id=c(1,1,1,1,1,2,2,2,2,3,3,3,3,3,3), 
      num=c(1,2,1,1,2,1,1,1,2,2,1,1,1,2,2)) 
df2$id <- as.factor(df2$id) 

Я хочу, чтобы найти идентификаторы, которые имеют возникновение менее 2 после первого вхождения 2. Например, это может подобрать идентификатор 1 , так как во второй строке есть 2, но для этого id следующие строки меньше 2).

Любые идеи?

+0

Я уверен, что мне нужно каким-либо образом использовать(), но я есть. Это точно, как – user85727

ответ

4

Звуки как работа за ?Position мне, хотя я не уверен, какой вывод вы хотите точно:

library(data.table) 
setDT(df2) 
df2[, Position(I,num==2) < Position(I,num < 2,right=TRUE,nomatch=FALSE), by=id] 
# id V1 
#1: 1 TRUE 
#2: 2 FALSE 
#3: 3 TRUE 

df2[, Position(I,num==2) < Position(I,num < 2,right=TRUE,nomatch=FALSE), by=id][,id[V1]] 
#[1] 1 3 
#Levels: 1 2 3 
+0

Спасибо, никогда не слышал об этой функции. – user85727

+0

Где находится? Позиция расположена? – user85727

+0

@ user85727 - набрав '? Position' в консоли R, вы получите помощь для' Position() '(и множество других полезных функций функционального программирования). – thelatemail

3

Решение с data.table. Кстати, в вашем примере идентификаторы 1 и 3 должны быть выбраны в качестве идентификатора 3 начинается с 2 и следующее значение 1.

#first chain removes all rows for each group up to and including the first 2 
#second chain returns the unique ids if a number less than 2 occurs 
setDT(df2)[, .SD[-(1:which(num == 2)[1]), ], by = 'id'][which(num < 2), .(id = unique(id))] 

Выходные:

id 
1: 1 
2: 3 

df2

> df2 
    id num 
1: 1 1 
2: 1 2 
3: 1 1 
4: 1 1 
5: 1 2 
6: 2 1 
7: 2 1 
8: 2 1 
9: 2 2 
10: 3 2 
11: 3 1 
12: 3 1 
13: 3 1 
14: 3 2 
15: 3 2 
2

Вот базовая версия R, использующая метод split-apply.

levels(df2$id)[sapply(split(df2$num, df2$id), 
         function(i) if(any(tail(i, -which.max(i==2)) < 2)) TRUE else FALSE)] 
[1] "1" "3" 

Я использовал levels, чтобы убедиться, что заказ будет следовать split. Функция решения в if использует any для сравнения усеченной версии вектора, который нарезается с использованием tail и which.max.