2016-07-29 4 views
2

Я новичок в R и пытаюсь удалить строки на основе значений предыдущих строк. Пример данных:R удалять строки на основе значений в предыдущих строках

Cust_ID | Date     | Value 
500219 | 2016-04-11 12:00:00 | 0 
500219 | 2016-04-12 16:00:00 | 0 
500219 | 2016-04-14 11:00:00 | 1 
500219 | 2016-04-15 12:00:00 | 1 
500219 | 2016-05-23 09:00:00 | 0 
500219 | 2016-05-02 19:00:00 | 0 
500220 | 2016-04-11 12:00:00 | 0 
500220 | 2016-04-14 11:00:00 | 1 
500220 | 2016-04-15 12:00:00 | 1 
500220 | 2016-05-23 09:00:00 | 0 
500220 | 2016-05-02 19:00:00 | 0 

Я хотел бы сохранить только те строки, прежде чем значение = 1 для каждого Cust_ID дает результат:

Cust_ID | Date     | Value 
500219 | 2016-04-11 12:00:00 | 0 
500219 | 2016-04-12 16:00:00 | 0 
500219 | 2016-04-14 11:00:00 | 1 
500219 | 2016-04-15 12:00:00 | 1 
500220 | 2016-04-11 12:00:00 | 0 
500220 | 2016-04-14 11:00:00 | 1 
500220 | 2016-04-15 12:00:00 | 1 

Любая помощь будет оценен по достоинству!

ответ

2

Ниже приведен метод split-apply-comb, который сохраняет значения 1, а также значения перед первым 1 для каждого клиента.

# split data by customer ID 
myList <- split(df, df$Cust_ID) 
# loop through ID list, drop desired rows, rbind resulting list 
dfNew <- do.call(rbind, lapply(myList, function(i) { 
           drop <- which(i$Value==1) 
           i[c(1:drop[1], drop[-1]),]})) 

который возвращает

dfNew 
     Cust_ID     Date Value 
500219.1 500219 2016-04-11 12:00:00  0 
500219.2 500219 2016-04-12 16:00:00  0 
500219.3 500219 2016-04-14 11:00:00  1 
500219.4 500219 2016-04-15 12:00:00  1 
500220.7 500220 2016-04-11 12:00:00  0 
500220.8 500220 2016-04-14 11:00:00  1 
500220.9 500220 2016-04-15 12:00:00  1 

Обратите внимание, что это решение не будет работать, если есть идентификаторы клиентов, которые никогда не имеют значение, равное 1.


Если вы хотите сохранить наблюдения которые никогда не достигают 1 порога, затем используйте

dfNew <- do.call(rbind, lapply(myList, function(i) { 
           drop <- which(i$Value==1) 
           if(length(drop) != 0) i[c(1:drop[1], drop[-1]),] 
           else i})) 
+0

Спасибо за ваше решение. К сожалению, я получаю следующую ошибку: Ошибка в 1: падение [1]: аргумент NA/NaN Любая помощь была бы принята с благодарностью! –

+0

Я предполагаю, что есть идентификаторы, в которых нет значений, равных 1. Это так? Если да, то что бы вы хотели с ними сделать? – lmo

+1

Спасибо за ваш ответ. Кажется, что падение порождает ошибку при пустом. Следующие работы! dfNew <- do.call (rbind, lapply (myList, function (i) { drop <- which (i $ Value == 1) if (length (drop)! = 0) { i [c (1: падение [1], падение [-1]),] } })) –

2

Мы можем использовать data.table. Преобразуйте 'data.frame' в 'data.table' (setDT(df1)), сгруппированный по 'Cust_ID', мы получим последовательность из max индексов, где 'Value' равно 1, и получите индекс строки (.I) и используйте это для подмножество строк данных.

library(data.table) 
setDT(df1)[df1[, if(any(Value == 1)) .I[seq(max(which(Value == 1)))] 
           else .I[1:.N] , by = Cust_ID]$V1] 
#  Cust_ID    Date Value 
#1: 500219 2016-04-11 12:00:00  0 
#2: 500219 2016-04-12 16:00:00  0 
#3: 500219 2016-04-14 11:00:00  1 
#4: 500219 2016-04-15 12:00:00  1 
#5: 500220 2016-04-11 12:00:00  0 
#6: 500220 2016-04-14 11:00:00  1 
#7: 500220 2016-04-15 12:00:00  1 

Или используя аналогичный подход с dplyr

library(dplyr) 
df1 %>% 
    group_by(Cust_ID) %>% 
    slice(if(any(Value==1)) seq(max(which(Value==1))) else row_number()) 
# Cust_ID    Date Value 
#  <int>    <chr> <int> 
#1 500219 2016-04-11 12:00:00  0 
#2 500219 2016-04-12 16:00:00  0 
#3 500219 2016-04-14 11:00:00  1 
#4 500219 2016-04-15 12:00:00  1 
#5 500220 2016-04-11 12:00:00  0 
#6 500220 2016-04-14 11:00:00  1 
#7 500220 2016-04-15 12:00:00  1 
+0

альтернатива: setDT (mydf) [, .SD [seq (max (который (значение == 1)))], by = Cust_ID] '(немного лучше читаемый imo, но, возможно, медленнее на больших наборах данных) – Jaap

+0

@ Фрэнк исправлен. Спасибо за этот край. – akrun

+1

@Frank Спасибо за комментарий. – akrun

0

подход Повторение петли:

cust <- 0 
keep <- FALSE 
keepers <- vector(mode = "logical", length = nrow(df)) 

## walk through the dataframe backwards 
for(rec in nrow(df):1) 
{ 
    ## have we been working with this customer? 
    if(df[rec,]$Cust_ID == cust) 
    { 
    if(df[rec,]$Value == 1 | keep == TRUE) 
    { 
     keepers[rec] = TRUE 
     keep <- TRUE 
    } 
    } 
    else 
    { 
    cust = df[rec,]$Cust_ID 
    if(df[rec,]$Value == 1) 
    { 
     keepers[rec] = TRUE 
     keep <- TRUE 
    } 
    else 
    { 
     keep <- FALSE 
    } 
    } 
} 

df <- df[keepers,] 
df 
Смежные вопросы