Условный счетчик изменений с течением времени?

Я хотел бы подсчитать количество изменений переменной бинарного фактора. Эта переменная может время от времени изменяться туда и обратно несколько раз для каждого идентификатора пользователя. Теперь я хотел бы подсчитать количество изменений для каждого идентификатора пользователя в этой переменной за заданный промежуток времени.

Данные сортируются по идентификатору, году, месяцу, моему фактору. Я пробовал это в MySQL, но пока безуспешно. Есть ли простой способ сделать это в R? Я думал о добавлении еще одного столбца в мой data.frame и добавлении условий шаг за шагом ... Может быть, что-то% в%?

Заранее спасибо за предложения...

Хм, конечно... вот пример - извините, что сразу не привёл, голова болит ;):


   myf   Year    month userid   
  1 A    2005       1    260           
  2 B    2005       2    260           
  3 B    2005       4    260           
  4 A    2005       5    260           
  5 B    2005       6    260           
  6 B    2005       1    261 

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

  user  changes
   260     3
   260     0

и так далее...

ХТН


person Matt Bannert    schedule 25.10.2010    source источник
comment
Можно нам пример, пожалуйста? Или хотя бы примерные данные...   -  person Joshua Ulrich    schedule 25.10.2010
comment
+1 за то, что ты прав...   -  person Matt Bannert    schedule 25.10.2010
comment
В вашем примере не должно быть 3 и 0? Потому что пользователь 261 не меняется. И это означает, что A-B и A-A означают 1 изменение.   -  person Marek    schedule 25.10.2010
comment
да, Марек, ты прав. отредактировал это и скоро назову это днем. спасибо   -  person Matt Bannert    schedule 25.10.2010


Ответы (3)


Еще одно редактирование:

Учитывая ваши ответы на другие решения, вы можете получить то, что хотите, в одной строке:

Data$extra <- ave(as.integer(Data$myf),Data$id,FUN=function(x) sum(diff(x)!=0))

В этом случае слияние не требуется.


«За заданный промежуток времени» означает, что вы можете выбрать промежуток времени, а затем применить функцию. Ответ Джошуа - самый быстрый способ. Есть более общая функция, которая дает вам больше информации о длинах и значениях серий, rle. Обязательно проверьте это.

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

Изменить: я обновил ответ, чтобы показать вам, как легко преобразовать столбцы года и месяца в дату. Вы также должны использовать as.numeric при применении всего этого к фактору, подобному вашему.

#Testdata
set.seed(21)
Data <- data.frame(id=rep(letters[1:3],each=24),
                   year= rep(rep(c(2005,2006),each=12),6),
                   month=rep(1:12,6),
                   myf=sample(c("A","B"),24*3,TRUE))

#transformation
Data$dates <- as.Date(paste(Data$year,Data$month,"1",sep="-"))
#function

cond.count <- function(from,to,data){
    x <- data[data$dates>from & data$dates<to,]
    tapply(as.numeric(x$myf),x$id,function(y)sum(diff(y)!=0))
}

#example
from <- as.Date("2005-01-01")
to <- as.Date("2006-04-15")

cond.count(from,to,Data)
person Joris Meys    schedule 25.10.2010
comment
Класс yearmon в zoo удобен, когда вам нужна только месячная гранулярность. - person Joshua Ulrich; 25.10.2010
comment
@Джошуа: очень верно. Обычно я использую класс Date, так как другие пакеты я использую неохотно, учитывая проблемы, которые они могут доставить. Но в данном случае это было бы лучшим решением. - person Joris Meys; 25.10.2010
comment
Как я так постоянно упускаю из виду ave? Отличное решение! - person Joshua Ulrich; 25.10.2010

Вот мое предположение.

set.seed(21)
Data <- data.frame(id=sample(letters[1:3],20,TRUE),
                   date=sample(1:3,20,TRUE),
                   myfactor=sample(0:1,20,TRUE))
Data <- Data[order(Data$id,Data$date),]

DataCh <- aggregate(Data[,"myfactor",FALSE],
            by=Data[,c("id","date")], function(x) sum(diff(x)!=0))
DataCh <- DataCh[order(DataCh$id,DataCh$date),]

РЕДАКТИРОВАТЬ: Вот обновление с данными вашего примера.

lines <- "   myf   Year    month userid   
 1 A    2005       1    260           
 2 B    2005       2    260           
 3 B    2005       4    260           
 4 A    2005       5    260           
 5 B    2005       6    260           
 6 B    2005       1    261 "

Data <- read.table(con <- textConnection(lines)); close(con)

DataCh <- aggregate(Data[,"myf",FALSE],
            by=Data[,"userid",FALSE], function(x) sum(diff(unclass(x))!=0))

merge(Data,DataCh,by="userid",suffixes=c("",".change"))
#   userid myf Year month myf.change
# 1    260   A 2005     1          3
# 2    260   B 2005     2          3
# 3    260   B 2005     4          3
# 4    260   A 2005     5          3
# 5    260   B 2005     6          3
# 6    261   B 2005     1          0
person Joshua Ulrich    schedule 25.10.2010

person    schedule
comment
Это чертовски близко к тому, что мне нужно. Прямо сейчас мне нужно преобразовать myf в какую-то реальную переменную TRUE/FALSE. С данными Ричи Коттона все работает нормально. С моим собственным я просто получаю: Ошибка в r[i1] - r[-length(r):-(length(r) - lag + 1L)]: нечисловой аргумент бинарного оператора... но, вероятно, я разберись с этим.. - person Matt Bannert; 25.10.2010
comment
Чтобы преобразовать двухуровневую переменную factor в переменную logical, попробуйте myf == "A" - person Richie Cotton; 25.10.2010
comment
@ran2 Для факторов используйте as.numeric или unclass. Например. split_by_id <- split(unclass(factor_variable), id)). - person Marek; 25.10.2010
comment
Это сработало отлично. после того, как я решил свои проблемы с логическими значениями, решением было преобразование их в логическую переменную. Должен ли я использовать слияние для добавления вновь полученной информации в мой набор данных? Или я могу просто привязать его, потому что на сортировку это не влияет? - person Matt Bannert; 25.10.2010
comment
@ran2: вам нужно объединить userid (см. мой ответ) - person Joshua Ulrich; 25.10.2010
comment
Если это действительно все, что вам нужно, это легко сделать с помощью однострочника: Data$extra ‹- ave(as.integer(Data$myf),Data$id,FUN=function(x) sum(diff(x)!= 0)) - person Joris Meys; 25.10.2010
comment
Черт, с помощью Ричи Коттона я решил ее за 2 строки. Теперь это возможно даже в одну строку. Большое спасибо, к сожалению, у меня недостаточно приемов для вас всех! пару часов назад я понятия не имел, как решить эту проблему, и отчаянно занимался SQL. Тем не менее, я действительно не понимаю, что усредняется (см. Справку) с помощью этой функции ave... - person Matt Bannert; 25.10.2010