2016-12-16 7 views
0

Ищите помощь для написания сложного фрагмента кода R.Найти и сопоставить ближайшее значение строки на основе критерия

У меня есть кадр данных следующей структуры:

#make fake data 
category<-c("a", "a", "a", "a", "a", "b", "b", "b", "b", "b") 
cat.id<-rep(1:5, 2) 
time <- seq.POSIXt(as.POSIXct("10/24/16 21:05", format="%m/%d/%y %H:%M", tz="America/Chicago"), by="5 min", length.out=10) 
x<-c(0.2, 3, 4, 0.5, 1.4, 3, 1.9, 2.2, 4, 1.2) 

data<-data.frame(category, cat.id, time, x) 

>data 
    category cat.id    time x 
1   a  1 2016-10-24 21:05:00 0.2 
2   a  2 2016-10-24 21:10:00 3.0 
3   a  3 2016-10-24 21:15:00 4.0 
4   a  4 2016-10-24 21:20:00 0.5 
5   a  5 2016-10-24 21:25:00 1.4 
6   b  1 2016-10-24 21:30:00 3.0 
7   b  2 2016-10-24 21:35:00 1.9 
8   b  3 2016-10-24 21:40:00 2.2 
9   b  4 2016-10-24 21:45:00 4.0 
10  b  5 2016-10-24 21:50:00 1.2 

Для каждого подмножества «категории» (например, «а» или «б»), мне нужно перенести «cat.id», такие что: -if «x» равно < 2, тогда «cat.id» сопоставляется (или сдвигается) до ближайшего предыдущего значения «cat.id», где x is> = 2. -сдвинутый «cat.id» «значение сохраняется в столбце« cat.idshifted » -Для значений« cat.id »== 1 сдвиг отсутствует, поскольку для этого подмножества« категории »нет предшествующего значения

Это будет производить кадр данных, как:

data$cat.idshifted<-c(1, 2, 3, 3, 3, 1, 1, 3, 4, 4) 
>data 
    category cat.id    time x cat.idshifted 
1   a  1 2016-10-24 21:05:00 0.2    1 
2   a  2 2016-10-24 21:10:00 3.0    2 
3   a  3 2016-10-24 21:15:00 4.0    3 
4   a  4 2016-10-24 21:20:00 0.5    3 
5   a  5 2016-10-24 21:25:00 1.4    3 
6   b  1 2016-10-24 21:30:00 3.0    1 
7   b  2 2016-10-24 21:35:00 1.9    1 
8   b  3 2016-10-24 21:40:00 2.2    3 
9   b  4 2016-10-24 21:45:00 4.0    4 
10  b  5 2016-10-24 21:50:00 1.2    4 

Основная идея заключается в том, что «cat.id» представляет количество собранных файлов данных для «категории». Иногда файлы данных, которые фактически принадлежат одному событию, разбиваются на несколько файлов из-за проблем с оборудованием. Таким образом, 1 событие данных может быть собрано в 3 файла. Вы можете выяснить, какие файлы идут вместе, глядя на «x». Если значение x < 2, то файлы идут вместе. И так как 1 файл можно разбить на многие, последовательность x < 2 будет представлять несколько файлов, которые принадлежат друг другу.

Так что я хочу сделать, это индекс/найти каждый раз, когда x < 2, и отрегулируйте «cat.id» или идентификатор файла до правильного значения, которое происходит, когда ближайший по времени предыдущий файл с x> = 2.

Я думаю, что функция, которая индексирует ближайшее (по времени)> = 2 значение «x», может быть уместным. Затем индексированное значение вернет значение «cat.id» в значение «cat.idshifted».

Я знаком с which.max и т. Д., Чтобы индексировать значения, однако я не знаю, как индексировать значения, говоря «дайте мне то, что является самым близким предыдущим значением».

Я не включал здесь для простоты, но x на самом деле представляет собой количество времени между каждой коллекцией файлов. Например, это сложный объект. Может быть, цикл while может работать? Где: -когда есть х < 2 значения -Shift значение cat.id назад 1 (например, cat.id-1) -Recompute difftime -Check если есть еще значения х < 2, не повторяется, если до тех пор не правда.

Любые мысли об этой сложной части кода?

+1

хорошо поймать и острый глаз! отредактирован для исправления. – griffmer

+0

Не может ответить на вопрос, но для «дайте мне то, что является ближайшим предыдущим значением», это будет работать: 'y <-5.4 x <-rnorm (10,6,1) x [x <= y] [which.min (abs (x [x <= y] - y))] ' – Jean

ответ

1

Попробуйте это:

# Create 'temp' column to indicate whether record belongs to previous file (0) or not (cat.id) 
data$temp = ifelse(data$x < 2, 0, data$cat.id) 
data$temp[data$cat.id==1] = 1 

# Take the cumulative max of 'temp' by category. 
data$cat.idshifted = unlist(by(data, data$category, function(da) cummax(da$temp))) 

> data 
# category cat.id    time x temp cat.idshifted 
# 1   a  1 2016-10-24 21:05:00 0.2 1    1 
# 2   a  2 2016-10-24 21:10:00 3.0 2    2 
# 3   a  3 2016-10-24 21:15:00 4.0 3    3 
# 4   a  4 2016-10-24 21:20:00 0.5 0    3 
# 5   a  5 2016-10-24 21:25:00 1.4 0    3 
# 6   b  1 2016-10-24 21:30:00 3.0 1    1 
# 7   b  2 2016-10-24 21:35:00 1.9 0    1 
# 8   b  3 2016-10-24 21:40:00 2.2 3    3 
# 9   b  4 2016-10-24 21:45:00 4.0 4    4 
# 10  b  5 2016-10-24 21:50:00 1.2 0    4 
+0

Спасибо! Это работает и работает намного быстрее (примерно на 7 секунд быстрее), чем указано выше. У меня проблемы с пониманием того, как работает последняя строка кода. Я понимаю, что вы делаете до последней строки кода. Не могли бы вы немного расширить? Извиняюсь, я обычно не использую эти функции. – griffmer

+0

@griffmer 'by' разбивает данные на куски уникальными значениями' da $ category' и применяет определенную мной функцию, которая должна принимать кумулятивный максимум 'temp', каждому куску. Он возвращает список, поэтому вам нужно «unlist», чтобы получить вектор – sirallen

0
data$cat.idshifted <- NA 

for(c in data$category){ 
    for(i in which(data$category==c)){ 
    if(data$cat.id[i]==1){ 
     data$cat.idshifted[i] <- data$cat.id[i]  
    } else if(data$x[i]<=2){ 
     data$cat.idshifted[i] <- max(data$cat.id[data$x > 2 & data$category==c & data$cat.id < data$cat.id[i]]) 
     } else if(data$x[i]>2){ 
     data$cat.idshifted[i] <- data$cat.id[i] 
     } 
    } 
} 

data 
category cat.id    time x cat.idshifted 
1   a  1 2016-10-24 21:05:00 0.2    1 
2   a  2 2016-10-24 21:10:00 3.0    2 
3   a  3 2016-10-24 21:15:00 4.0    3 
4   a  4 2016-10-24 21:20:00 0.5    3 
5   a  5 2016-10-24 21:25:00 1.4    3 
6   b  1 2016-10-24 21:30:00 3.0    1 
7   b  2 2016-10-24 21:35:00 1.9    1 
8   b  3 2016-10-24 21:40:00 2.2    3 
9   b  4 2016-10-24 21:45:00 4.0    4 
10  b  5 2016-10-24 21:50:00 1.2    4 

Если вы хотите, чтобы сделать это немного короче, вы могли бы объединить с первым if и мой второй else if в одно if заявление с оператором |, но это работает, как есть.

Путь заявление:

max(data$cat.id[data$x > 2 & data$category==c & data$cat.id < data$cat.id[i]])

работы является то, что это говорит следующее:

  • Я хочу, чтобы моя замена cat.id соответствовать той, где значение x> 2, следовательно, data$x > 2 часть
  • Я хочу только найти одну и те же категории для замены (data$category==c)
  • Я хочу, чтобы замена предшествовать цели (data$cat.id < data$cat.id[i])
  • Я хочу, чтобы в ближайший ряд фитинг вышеуказанных критериев (именно поэтому вы используете max())
+1

Это работает фантастически. Извините за медленный ответ, мне понадобилось немного времени, чтобы перевести на мой собственный код. – griffmer

+0

@griffmer Рад, что он работает для вас –

 Смежные вопросы

  • Нет связанных вопросов^_^