Пустышка для первого нового элемента в серии - PullRequest
5 голосов
/ 03 февраля 2012

Предположим, у меня есть переменная, которая длится в течение нескольких периодов. Как количество лет, что у меня есть Ipod. Итак, у меня был Ipod 1-го поколения с 2001 по 2004 год, а затем в 2005 году у меня был Ipod 2 и так далее. Так что мой фрейм данных будет выглядеть так:

  2001 Ipod1
  2002 Ipod1
  2003 Ipod1
  2004 Ipod1
  2005 Ipod2
  2006 Ipod2
  2007 Ipod2
  2008 Ipod2
  2009 Ipod3
  2010 Ipod3

То, что я хочу, - это создать фиктив на период, когда прибудет новая переменная, чтобы я получил:

  Year  Var  Dummy
  2001 Ipod1  1
  2002 Ipod1  0
  2003 Ipod1  0
  2004 Ipod1  0
  2005 Ipod2  1
  2006 Ipod2  0
  2007 Ipod2  0
  2008 Ipod2  0
  2009 Ipod3  1
  2010 Ipod3  0

Пока я смог сделать это:

df = structure(list(Year = 2001:2010, Var = structure(c(1L, 1L, 1L,
1L, 2L, 2L, 2L, 2L, 3L, 3L), .Label = c("Ipod1", "Ipod2", "Ipod3"
), class = "factor")), .Names = c("Year", "Var"), class = "data.frame", row.names = c(NA,
-10L))

df$number.in.group = unlist(lapply(table(df$Var),seq.int)) 
df$dummy = ifelse(df$number.in.group == 1,1,0)
df$dummy[1]=0

На самом деле я бы хотел, чтобы первый элемент макета был равен нулю.

Мой вопрос: есть ли способ сделать это лучше?

Спасибо

Ответы [ 4 ]

10 голосов
/ 03 февраля 2012

Как насчет этого:

df$Dummy <- as.numeric(!duplicated(df$Var))

# Or, if you want the first element to be 0,
df$Dummy <- c(0, as.numeric(!duplicated(df$Var))[-1])
5 голосов
/ 03 февраля 2012

Я считаю, что это дает желаемый результат:

> df$Dummy <- c(0, diff(as.numeric(df$Var)))
> df
   Year   Var Dummy
1  2001 Ipod1     0
2  2002 Ipod1     0
3  2003 Ipod1     0
4  2004 Ipod1     0
5  2005 Ipod2     1
6  2006 Ipod2     0
7  2007 Ipod2     0
8  2008 Ipod2     0
9  2009 Ipod3     1
10 2010 Ipod3     0

Это работает, поскольку Var является фактором, поэтому использование as.numeric работает.

2 голосов
/ 03 февраля 2012

(1) Вопрос задан для столбца Dummy, но пример ответа на вопрос также вывел столбец number.in.group, поэтому я не был уверен, нужен ли столбец number.in.group или нет;однако ниже мы предполагаем, что это необходимо.Обратите внимание, что присвоение 0 первому элементу Dummy приводит к преобразованию этого столбца в числовой:

within(df, {
    number.in.group <- ave(Year, Var, FUN = seq_along)
    Dummy <- number.in.group == 1
    Dummy[1] <- 0
})

(2a) Если number.in.group не требуется и группы в Varявляются смежными, как в примере, тогда уже представленное решение duplicated было бы предпочтительным, за исключением того, что я думаю, что было бы немного яснее, если бы оно было написано так:

df$Dummy <- !duplicated(df$Var)
df$Dummy[1] <- 0

, хотя для этого требуется одно дополнительное утверждение.

(2b) Также мы могли бы предпочесть неразрушающую форму:

within(df, {
    Dummy <- !duplicated(Var)
    Dummy[1] <- 0
})
2 голосов
/ 03 февраля 2012

Функция rle очень полезна в подобных ситуациях. Он находит последовательные прогоны одного и того же элемента в векторе.

rle_result = rle(as.character(df$Var))
rle_result
Run Length Encoding
  lengths: int [1:3] 4 4 2
  values : chr [1:3] "Ipod1" "Ipod2" "Ipod3"

Чтобы создать новую переменную:

df$new = 0
change_ids = 1 + cumsum(rle_result$lengths)
df$new[change_ids[-length(change_ids)]] <- 1
df
   Year   Var new
1  2001 Ipod1   0
2  2002 Ipod1   0
3  2003 Ipod1   0
4  2004 Ipod1   0
5  2005 Ipod2   1
6  2006 Ipod2   0
7  2007 Ipod2   0
8  2008 Ipod2   0
9  2009 Ipod3   1
10 2010 Ipod3   0

Я думаю, это именно то, что вы искали.

...