R Зацикливание уникальных значений в столбце данных, чтобы создать другое на основе условий - PullRequest
0 голосов
/ 21 января 2019

Мой набор данных состоит из баллов и общего числа респондентов, ответивших на вопросы, заданные в ходе опроса, в течение ряда финансовых лет (2013 ФГ, 14 ФГ и 15 ФГ) и в разных регионах.

Моя цель состоит в том, чтобы пройтись по FY и укажите, когда задавался каждый вопрос, для каждого региона.И сохраните эту информацию в новом столбце.

Вот так выглядит воспроизводимый образец -

testdf=data.frame(FY=c("FY13","FY14","FY15","FY14","FY15","FY13","FY14","FY15","FY13","FY15","FY13","FY14","FY15","FY13","FY14","FY15"),
              Region=c(rep("AFRICA",5),rep("ASIA",5),rep("AMERICA",6)),
              QST=c(rep("Q2",3),rep("Q5",2),rep("Q2",3),rep("Q5",2),rep("Q2",3),rep("Q5",3)),
              Very.Satisfied=runif(16,min = 0, max=1),
              Total.Very.Satisfied=floor(runif(16,min=10,max=120)),
              Satisfied=runif(16,min = 0, max=1),
              Total.Satisfied=floor(runif(16,min=10,max=120)),
              Dissatisfied=runif(16,min = 0, max=1),
              Total.Dissatisfied=floor(runif(16,min=10,max=120)),
              Very.Dissatisfied=runif(16,min = 0, max=1),
              Total.Very.Dissatisfied=floor(runif(16,min=10,max=120)))

Я начинаю с создания столбца идентификатора, объединяя Region & QST

library(tidyr)
testdf = testdf %>%
unite(ID,c('Region','QST'),sep = "",remove = F)

Моя цель

1) Для каждого уникального ID укажите, был ли задан данный вопрос -

a) Только наодин год (либо в 2013 финансовом году, либо в 2013 финансовом году)

b) в течение последних двух лет (только в 2015 финансовом году и в 2014 финансовом году)

в) в течение последних трех лет (в 2015 финансовом году и в 2014 финансовом году)

d) Только для FY13 и FY15

Моя попытка

Для этой проблемы я попытался создать for loop и для каждого уникального ID, я сначала сохраняю уникальные случаи каждого финансового года, на который был задан вопрос, в векторе v.Затем, используя условный оператор IF, я назначаю комментарий для вновь созданного столбца с именем Tally на основе этих случаев.

for (i in unique(testdf$ID))
{
v=unique(testdf$FY)

  if(('FY15' %in% v) & ('FY14' %in% v)) {
      testdf$Tally=='Asked Over The Past Two Years'
  } 
  else if(('FY15' %in% v) & ('FY14' %in% v) & ('FY13' %in% v)) {
       testdf$Tally=='Asked Over The Past Three Years'
  }
  else if(('FY13' %in% v) & ('FY15' %in% v)) {
        testdf$Tally=='Question Asked in FY13 & FY15 Only'
  }
  else { testdf$Tally=='Question Asked Once Only' 
  }

}  

Цикл, кажется, выполняется без выдачи сообщения об ошибке, но не кажется,для создания нового столбца Tally.

Любая помощь с этим будет принята с благодарностью.

Ответы [ 4 ]

0 голосов
/ 21 января 2019

Есть решение, использующее ваш столбец ID.(Используя paste0, мы можем сделать это несколько лучше, хотя с testdf$ID <- paste0(testdf$Region, "_", testdf$QST).)

Мы dcast ваш testdf, используя пакет reshape2.

library(reshape2)
tmp <- dcast(testdf, ID ~ FY, 
               value.var="QST", fun.aggregate=length)

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

tmp <- cbind(tmp, 
             past2=as.numeric(t2[3] + t2[4] == 2 & t2[2] == 0), 
             past3=as.numeric(t2[2] + t2[3] + t2[4] == 3),
             y13_15=as.numeric(t2[2] + t2[4] == 2 & t2[3] == 0))

Последовательности в столбцах 5: 7 содержат требуемую Tally информацию, которую мы можем доить

tmp$Tally <- apply(tmp, 1, function(x) paste0(x[5:7], collapse=""))

перевести на человеческий язык по уровням факторов,

tmp$Tally <- factor(tmp$Tally, labels=c('Question Asked Once Only',
                                        'Question Asked in FY13 & FY15 Only',
                                        'Asked Over The Past Three Years',
                                        'Asked Over The Past Two Years'))

и объединить с исходным фреймом данных для достижения желаемого результата.

Результат

> merge(testdf, t3[c(1, 8)])
             ID   FY    Region QST                              Tally
1     AFRICA_Q2 FY13    AFRICA  Q2    Asked Over The Past Three Years
2     AFRICA_Q2 FY14    AFRICA  Q2    Asked Over The Past Three Years
3     AFRICA_Q2 FY15    AFRICA  Q2    Asked Over The Past Three Years
4     AFRICA_Q5 FY14    AFRICA  Q5      Asked Over The Past Two Years
5     AFRICA_Q5 FY15    AFRICA  Q5      Asked Over The Past Two Years
6    AMERICA_Q2 FY13   AMERICA  Q2    Asked Over The Past Three Years
7    AMERICA_Q2 FY14   AMERICA  Q2    Asked Over The Past Three Years
8    AMERICA_Q2 FY15   AMERICA  Q2    Asked Over The Past Three Years
9    AMERICA_Q5 FY13   AMERICA  Q5    Asked Over The Past Three Years
10   AMERICA_Q5 FY14   AMERICA  Q5    Asked Over The Past Three Years
11   AMERICA_Q5 FY15   AMERICA  Q5    Asked Over The Past Three Years
12 ANTH.CTRY_Q2 FY15 ANTH.CTRY  Q2           Question Asked Once Only
13      ASIA_Q2 FY13      ASIA  Q2    Asked Over The Past Three Years
14      ASIA_Q2 FY14      ASIA  Q2    Asked Over The Past Three Years
15      ASIA_Q2 FY15      ASIA  Q2    Asked Over The Past Three Years
16      ASIA_Q5 FY13      ASIA  Q5 Question Asked in FY13 & FY15 Only
17      ASIA_Q5 FY15      ASIA  Q5 Question Asked in FY13 & FY15 Only

Данные

testdf <- structure(list(FY = c("FY13", "FY14", "FY15", "FY14", "FY15", 
"FY13", "FY14", "FY15", "FY13", "FY15", "FY13", "FY14", "FY15", 
"FY13", "FY14", "FY15", "FY15"), Region = c("AFRICA", "AFRICA", 
"AFRICA", "AFRICA", "AFRICA", "ASIA", "ASIA", "ASIA", "ASIA", 
"ASIA", "AMERICA", "AMERICA", "AMERICA", "AMERICA", "AMERICA", 
"AMERICA", "ANTH.CTRY"), QST = c("Q2", "Q2", "Q2", "Q5", "Q5", 
"Q2", "Q2", "Q2", "Q5", "Q5", "Q2", "Q2", "Q2", "Q5", "Q5", "Q5", 
"Q2")), row.names = c(NA, 17L), class = "data.frame")
0 голосов
/ 21 января 2019

Нет необходимости в цикле:

library(tidyverse)

result <- testdf %>%
    select(3, 2, 1) %>%
    mutate(Asked = 1) %>%
    spread(FY, Asked)

> result
  QST  Region FY13 FY14 FY15
1  Q2  AFRICA    1    1    1
2  Q2 AMERICA    1    1    1
3  Q2    ASIA    1    1    1
4  Q5  AFRICA   NA    1    1
5  Q5 AMERICA    1    1    1
6  Q5    ASIA    1   NA    1

Ответы на все четыре вопроса за один раз.

Если вам действительно нужен столбец подсчета, разверните его следующим образом:

result %>%
    mutate(Tally = case_when(FY13 + FY14 + FY15 == 1 ~ "Only one year",
                             FY13 + FY14 + FY15 == 3 ~ "Past three years",
                             FY14 + FY15 == 2 ~ "Past two years",
                             FY13 + FY15 == 2 ~ "FY13 and FY15 only",
                             NA ~ NA_character_))

  QST  Region FY13 FY14 FY15              Tally
1  Q2  AFRICA    1    1    1   Past three years
2  Q2 AMERICA    1    1    1   Past three years
3  Q2    ASIA    1    1    1   Past three years
4  Q5  AFRICA   NA    1    1     Past two years
5  Q5 AMERICA    1    1    1   Past three years
6  Q5    ASIA    1   NA    1 FY13 and FY15 only
0 голосов
/ 21 января 2019

Рассмотрим ave для группировки расчетов по Регион и QST внутри вложенного ifelse для условной логики:

testdf <- within(testdf, {
                   FY13 <- ifelse(FY=='FY13', 1, 0)
                   FY14 <- ifelse(FY=='FY14', 1, 0)
                   FY15 <- ifelse(FY=='FY15', 1, 0)

                   Tally <- ifelse(ave(FY13, Region, QST, FUN=max) + ave(FY14, Region, QST, FUN=max) + ave(FY15, Region, QST, FUN=max) == 1,
                                   'Asked Only on One Year',
                                   ifelse(ave(FY13, Region, QST, FUN=max) + ave(FY14, Region, QST, FUN=max) + ave(FY15, Region, QST, FUN=max) == 3,
                                          'Asked Over the Past Three Years',
                                          ifelse(ave(FY14, Region, QST, FUN=max) + ave(FY15, Region, QST, FUN=max) == 2,
                                                 'Asked Over the Past Two Years',
                                                 ifelse(ave(FY13, Region, QST, FUN=max) + ave(FY15, Region, QST, FUN=max) == 2,
                                                        'Asked On FY13 & FY15 Only',
                                                        NA
                                                        )
                                                 )
                                          )
                                   )

                   FY13 <- NULL; FY14 <- NULL; FY15 <- NULL
             })

testdf[c("ID", "FY", "Tally")]

#     Region QST   FY                           Tally
# 1   AFRICA  Q2 FY13 Asked Over the Past Three Years
# 2   AFRICA  Q2 FY14 Asked Over the Past Three Years
# 3   AFRICA  Q2 FY15 Asked Over the Past Three Years
# 4   AFRICA  Q5 FY14   Asked Over the Past Two Years
# 5   AFRICA  Q5 FY15   Asked Over the Past Two Years
# 6     ASIA  Q2 FY13 Asked Over the Past Three Years
# 7     ASIA  Q2 FY14 Asked Over the Past Three Years
# 8     ASIA  Q2 FY15 Asked Over the Past Three Years
# 9     ASIA  Q5 FY13       Asked On FY13 & FY15 Only
# 10    ASIA  Q5 FY15       Asked On FY13 & FY15 Only
# 11 AMERICA  Q2 FY13 Asked Over the Past Three Years
# 12 AMERICA  Q2 FY14 Asked Over the Past Three Years
# 13 AMERICA  Q2 FY15 Asked Over the Past Three Years
# 14 AMERICA  Q5 FY13 Asked Over the Past Three Years
# 15 AMERICA  Q5 FY14 Asked Over the Past Three Years
# 16 AMERICA  Q5 FY15 Asked Over the Past Three Years
0 голосов
/ 21 января 2019

В вашем коде основная проблема заключается в том, что в предложении if-else вы делаете не присваивание (используя «<-»), а сравнение, используя «==». Вот решение, которое я считаю более элегантным, поскольку оно не использует цикл: </p>

require(tidyverse)

testdf %>%
  select(ID, FY) %>%
  unique() %>%
  mutate(is_true = 1) %>%
  spread(key = FY, value = is_true, fill = 0) %>%
  mutate(tally = case_when(
    FY13 == 1 & FY14 == 1 & FY15 == 1 ~ 'Asked Over The Past Three Years',
                FY14 == 1 & FY15 == 1 ~ 'Asked Over the Past Two Years',
    FY13 == 1 &             FY15 == 1 ~ 'Asked in FY12 & FY15 Only',
    TRUE ~ 'Question Asked Once Only'
  ))

Выход:

+------------------------------------------------------------+
|          ID FY13 FY14 FY15                           tally |
+------------------------------------------------------------+
| 1  AFRICAQ2    1    1    1 Asked Over The Past Three Years |
| 2  AFRICAQ5    0    1    1   Asked Over the Past Two Years |
| 3 AMERICAQ2    1    1    1 Asked Over The Past Three Years |
| 4 AMERICAQ5    1    1    1 Asked Over The Past Three Years |
| 5    ASIAQ2    1    1    1 Asked Over The Past Three Years |
| 6    ASIAQ5    1    0    1       Asked in FY12 & FY15 Only |
+------------------------------------------------------------+
...