По группам сопоставьте значения с определенным значением - PullRequest
0 голосов
/ 16 мая 2018

У меня есть набор данных, который включает в себя результат голосования r для каждого избирателя v по конкретному решению d. Мои данные, таким образом, выглядят так:

d <- c(1,1,1,1,2,2,2,2,3,3,3,4,4,4,4)
v <- c(6,7,8,9,6,7,8,9,6,7,9,6,7,8,9)
r <- c(y,y,n,n,n,n,n,n,y,y,y,y,y,a,y)
df <- data.frame(d,v,r)

Не каждый избиратель голосует на каждых выборах. Что я хочу сделать, так это посмотреть, будут ли другие избиратели делать то же самое, что и конкретный избиратель (скажем, v == 8). Обычно я бы просто использовал dplyr:

df %>% group_by(d) %>% mutate(like8 = ifelse(r == r[v == 8], 1, 0))

Проблема, с которой я столкнулся, заключается в том, что этот конкретный избиратель v == 8 не имеет зарегистрированного голоса за каждое решение (что отличается от воздержавшихся голосов, которые записываются). Из-за этого я получаю следующую ошибку.

Ошибка в mutate_impl (.data, точки): Столбец like8 должен иметь длину 3 (размер группы) или единицу, а не 0

То, что я сделал до сих пор, - это написал комбинацию ifelse и looping, чтобы обойти эту проблему.

with(df,
    for (i in unique(d)) {
        if(8 %in% v){ 
            for (j in r[d == i]) {
            df$like8[d == i & r == j] <- ifelse(j == r[v == 8], 1, 0)
                                 }
                    } else {
            for (j in r[d == i]){
            df$like8[d == i & r == j] <- NA
                                } 
                           }
                         }
)

- примечание: я никогда официально не инструктировался в «хороших» соглашениях по программированию, поэтому мое расположение скобок, вероятно, неясно и открыто для предложений.

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

Ответы [ 3 ]

0 голосов
/ 16 мая 2018

Не ясно, ожидаемый результат.Если мы будем следовать методологии, описанной в ответе @Melissa Key, аналогичный подход в data.table (как упомянуто в посте ОП) будет

library(data.table)
setDT(df)[, like8 := if(8 %in% v) +(r == r[v == 8]) else NA_integer_, by = d]
df
#    d v r like8
# 1: 1 6 y     0
# 2: 1 7 y     0
# 3: 1 8 n     1
# 4: 1 9 n     1
# 5: 2 6 n     1
# 6: 2 7 n     1
# 7: 2 8 n     1
# 8: 2 9 n     1
# 9: 3 6 y    NA
#10: 3 7 y    NA
#11: 3 9 y    NA
#12: 4 6 y     0
#13: 4 7 y     0
#14: 4 8 a     1
#15: 4 9 y     0

Или мы избежим if/else путем разделенияэто два шага и назначить только тем, которые удовлетворяют условию (8 %in% v)

i1 <- setDT(df)[, .I[8 %in% v], by = d]$V1
df[i1, like8 := +(r == r[v==8]), by = d]

Другие значения в 'like8' по умолчанию будут заполнены данными NA

d <- c(1,1,1,1,2,2,2,2,3,3,3,4,4,4,4)
v <- c(6,7,8,9,6,7,8,9,6,7,9,6,7,8,9)
r <- c('y','y','n','n','n','n','n','n','y','y','y','y','y','a','y')
df <- data.frame(d,v,r)
0 голосов
/ 16 мая 2018

Другое решение, использующее 2 объединения:

#initialize column
DT1[, like8 := NA_integer_][
    #set to 0 if voter 8 voted on decision
    DT1[v==8L], like8 := 0L, on=.(d)][
        #set to 1 if other voters voted the same in a particular decision
        DT1[v==8L], like8 := 1L, on=.(d, r)]

данные:

library(data.table)
library(microbenchmark)

#generate dummy data
set.seed(0L)
numD <- 100L
numV <- 1e4L
DT <- unique(data.table(d=sample(numD, numD*numV, replace=TRUE),
    v=sample(numV, numD*numV, replace=TRUE)))
DT[, r:=sample(c('y','n','a'), .N, replace=TRUE)]
setorder(DT, d, v, r)

#set key to speed up the subsetting to voter
setkey(DT, d, v)

DT1 <- copy(DT)
0 голосов
/ 16 мая 2018

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

df %>% 
    group_by(d) %>% 
    mutate(
      like8 = {
        if (sum(v == 8) > 0) as.numeric(r == r[v == 8])
        else NA
      }
    )

Оборачивает тест в оператор if / else, проверяя, есть ли избиратель 8. Оператор as.numeric эквивалентен тому, что вы написали, но должен быть быстрее, когда ваш ответ равен 1 / 0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...