Хобрук: Ваш путь к мастерству в программировании

R Хранение коэффициентов регрессии в столбце фрейма данных по группам

У меня есть фрейм данных с результатами опроса. Результаты сохраняются в вертикальном формате. Фрейм данных выглядит так:

set.seed(1000)

df = data.frame(RESP_ID=c(rep(1,6),rep(2,8),rep(3,9),rep(4,5),rep(5,4),rep(6,10),rep(7,4),rep(8,8),rep(9,8),rep(10,10)),
                CLIENT=c(rep("A",6),rep("A",8),rep("A",9),rep("A",5),rep("A",4),rep("B",10),rep("B",4),rep("B",8),rep("B",8),rep("B",10)),
                QST=c(paste0("Q",c(1:6)),paste0("Q",c(1:8)),paste0("Q",c(1:9)),paste0("Q",c(1:5)),paste0("Q",c(1:4)),paste0("Q",c(1:10)),paste0("Q",c(1:4)),paste0("Q",c(1:8)),paste0("Q",c(1:8)),paste0("Q",c(1:10))),
                VALUE=round(runif(72,1,4),0))

Описание кадра данных

RESP_ID = идентификатор респондента. Каждый идентификатор соответствует одному респонденту. В этом выборочном фрейме данных у нас есть 10 респондентов.

КЛИЕНТ = Соответствует имени клиента, чьи респонденты были опрошены. В этом примере фрейма данных у нас есть два клиента (A и B).

QST = соответствует номеру вопроса в опросе.

ЗНАЧЕНИЕ = соответствует варианту ответа на вопрос. Все вопросы имеют 4 варианта ответа (от 1 до 4).

Цель

Для каждой комбинации клиента и вопроса я хотел бы создать отдельный столбец, в котором будет храниться коэффициент регрессии для этого вопроса, регрессированного до Q2, в столбце QST.

Таким образом, в модели регрессии Q2 является зависимой переменной, а все остальные вопросы являются независимыми переменными.

Моя попытка

Моя попытка не дает мне желаемого результата.

slopesdf = df %>%
  spread(QST, VALUE, fill = 0) %>%
  group_by(CLIENT) %>%
  mutate(COEFFICIENT=lm(Q2 ~ .))

Я пытаюсь сначала сгруппировать по CLIENT и QST, а затем найти наклоны для каждого вопроса, регрессированного с помощью Q2. Я уверен, что есть лучший способ сделать это.

В настоящее время моя попытка дает мне следующее сообщение об ошибке:

Ошибка в mutate_impl(.data, dots): Ошибка оценки: '.' по формуле и аргументу «данные»

Желаемый результат

Я хотел бы, чтобы окончательный фрейм данных содержал три столбца: один для CLIENT, один для QST и третий, называемый COEFFICIENT, с коэффициентами для каждой комбинации CLIENT и QST, регрессировавшими с Q2 в качестве переменной ответа.

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

10.05.2019

  • Вы используете Q2, который не является столбцом 10.05.2019
  • Спасибо. Есть ли подход, который вы бы порекомендовали для получения желаемого результата? 10.05.2019
  • Мне непонятно, о чем вы спрашиваете. Q2 не является ни столбцом, ни числовым значением (переменная ответа для линейной модели должна быть числовой). QST — это столбец, но он категориальный, поэтому он не может быть зависимой (отклик) переменной в регрессии: я мог представить, что вы хотите VALUE~QST для каждого CLIENT (что фактически было бы дисперсионным анализом, поскольку QST является категориальным), но VALUE~Q2 не имеет смысла, потому что у предиктора есть только одно значение... можете ли вы показать нам результат одной конкретной регрессии, которую вы хотите сделать вручную? 10.05.2019
  • Можете ли вы запустить эту модель и убедиться, что это именно то, что вы действительно хотите сделать? Это правильная модель для этих данных? 10.05.2019
  • Попробуйте df %>% spread(QST, VALUE, fill = 0) %>% group_by(CLIENT) %>% nest %>% mutate(data = map(data, ~ .x %>% summarise(out = list(lm(Q2 ~ ., data = .x) %>% tidy)))) %>% unnest %>% unnest 10.05.2019
  • Этот набор данных имеет вертикальный формат, и перед запуском регрессии его необходимо преобразовать в горизонтальный формат. В идеале я бы хотел, чтобы значения в столбце QST были заголовками столбцов. И значения в столбце VALUE должны быть значениями в каждом столбце вопросов. Распространение фрейма данных будет первым шагом. После этого шага у нас будет столбец «Q2», который будет числовым, и это будет наша переменная ответа в нашей регрессионной модели. 10.05.2019
  • @Varun Можете ли вы попробовать код, который я прокомментировал? 10.05.2019
  • @akrun Я попробовал ваше решение. Но он не возвращает коэффициенты для всех вопросов. 10.05.2019
  • Я отредактировал вопрос, чтобы было понятнее 10.05.2019
  • Для меня это возвращение 11.05.2019

Ответы:


1

Я не уверен на 100%, что этот вывод - это то, что вам нужно, но на правильном ли это пути?

df2 <- df %>%
  spread(QST, VALUE, fill = 0) %>%
  split(.$CLIENT) %>%
  lapply(., function(x) { lm(Q2 ~ ., x[, -c(1,2)])$coefficients }) %>%
  do.call(rbind, .) %>%
  data.frame(.) %>%
  mutate(CLIENT = rownames(.)) %>%
  gather(QST, COEFFICIENT, -CLIENT) %>%
  arrange(CLIENT)


> df2
   CLIENT          QST   COEFFICIENT
1       A X.Intercept. -1.200000e+01
2       A           Q1  1.000000e+00
3       A          Q10            NA
4       A           Q3  2.000000e+00
5       A           Q4  3.000000e+00
6       A           Q5  5.000000e-01
7       A           Q6            NA
8       A           Q7            NA
9       A           Q8            NA
10      A           Q9            NA
11      B X.Intercept.  5.000000e+00
12      B           Q1 -1.326970e-16
13      B          Q10  1.666667e+00
14      B           Q3  3.726559e-15
15      B           Q4 -2.000000e+00
16      B           Q5            NA
17      B           Q6            NA
18      B           Q7            NA
19      B           Q8            NA
20      B           Q9            NA

Изменить:

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

df %>%
  spread(QST, VALUE, fill = 0) %>%
  split(.$CLIENT) 

$A
  RESP_ID CLIENT Q1 Q10 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9
1       1      A  4   0  1  4  3  3  2  0  0  0
2       2      A  2   0  2  2  3  2  4  4  3  0
3       3      A  2   0  2  3  3  1  2  4  2  3
4       4      A  3   0  3  4  2  1  0  0  0  0
5       5      A  3   0  4  4  3  0  0  0  0  0

$B
   RESP_ID CLIENT Q1 Q10 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9
6        6      B  3   2  3  2  3  2  2  1  3  3
7        7      B  2   0  3  2  2  0  0  0  0  0
8        8      B  3   0  2  4  1  3  3  2  3  0
9        9      B  2   0  1  4  2  1  3  1  2  0
10      10      B  3   2  3  3  3  3  4  2  3  3

Обратите внимание, что все нули заполняются для вопросов, в которых ваши исходные данные не имели значений, если на вопрос не был дан ответ. См. ответ Бена Болкера по этому поводу.

Если вы теперь включите код для запуска lm для каждого из них, вы получите значения коэффициентов напрямую, которые включают значения NA, показанные выше:

> df %>%
+   spread(QST, VALUE, fill = 0) %>%
+   split(.$CLIENT) %>%
+   lapply(., function(x) { lm(Q2 ~ ., x[, -c(1,2)])$coefficients })
$A
(Intercept)          Q1         Q10          Q3          Q4          Q5          Q6          Q7          Q8          Q9 
  6.6666667   2.0000000          NA  -1.6666667  -0.6666667  -1.6666667          NA          NA          NA          NA 

$B
(Intercept)          Q1         Q10          Q3          Q4          Q5          Q6          Q7          Q8          Q9 
       13.0        -3.0        -0.5        -2.0          NA         2.0          NA          NA          NA          NA 

Редактировать 2:

Просто чтобы изучить более полный набор данных, если мы используем этот df:

set.seed(42)
df <-
  expand.grid(RESP_ID = 1:10,
              CLIENT = c("A", "B"),
              QST = paste("Q", 1:10, sep = "")) %>%
  mutate(VALUE = round(runif(200, 1, 4), 0))

и запускаем тот же код, получаем коэффициенты без значений NA:

> df %>%
+   spread(QST, VALUE, fill = 0) %>%
+   split(.$CLIENT) %>%
+   lapply(., function(x) { lm(Q2 ~ ., x[, -c(1,2)])$coefficients }) %>%
+   do.call(rbind, .) %>%
+   data.frame(.) %>%
+   mutate(CLIENT = rownames(.)) %>%
+   gather(QST, COEFFICIENT, -CLIENT) %>%
+   arrange(CLIENT)
   CLIENT          QST COEFFICIENT
1       A X.Intercept.  6.50000000
2       A           Q1 -4.14285714
3       A           Q3  2.50000000
4       A           Q4  0.85714286
5       A           Q5  1.00000000
6       A           Q6 -0.64285714
7       A           Q7 -1.21428571
8       A           Q8 -1.85714286
9       A           Q9  2.50000000
10      A          Q10 -0.07142857
11      B X.Intercept. -4.69924812
12      B           Q1 -0.86466165
13      B           Q3  1.56390977
14      B           Q4  1.10150376
15      B           Q5 -0.86842105
16      B           Q6  0.87593985
17      B           Q7  0.57142857
18      B           Q8  0.25187970
19      B           Q9  0.79699248
20      B          Q10 -0.12781955
10.05.2019
  • Это выглядит очень близко к тому, что я имею в виду. Вы знаете, почему существуют АН? 10.05.2019
  • @Varun - я полагаю, что-то связанное с данными. Если вы запустите функцию lm непосредственно в разделенных кадрах данных, это выходные значения для каждого Q - я добавлю к своему ответу, чтобы продемонстрировать 10.05.2019

  • 2

    Решение, которое следует логике моего мозга (нам нужно, чтобы Q2 была доступна как отдельная переменная... как только мы переупорядочим данные таким образом, мы сможем запустить (значения NA определенно связаны с недостатками в этом крошечном наборе данных). - случаи, когда у предиктора нет вариации, поэтому ответ нельзя оценить...)

    (df
        %>% group_by(RESP_ID,CLIENT)
        ## add a new variable for Q2
        %>% mutate(Q2=VALUE[QST=="Q2"])
        ## drop the old one
        %>% filter(QST!="Q2")
        %>% group_by(CLIENT,QST)
        ## run the regression by group; return a data frame
        %>% do(as.data.frame(rbind(coef(lm(Q2~VALUE,data=.)))))
        ## convert wide coefficients to long
        %>% tidyr::gather(coef,value,-c(CLIENT,QST))
        %>% arrange(CLIENT)
    )
    
    10.05.2019

    3

    Для таких задач мне нравится подход «множество моделей» из R для науки о данных. Он соответствует стилю tidyverse, используя вложенные фреймы данных и purrr::map для создания столбца списка моделей. Затем broom::tidy предоставляет утилиты для извлечения необходимой информации о моделях.

    Я удалил столбец идентификатора, чтобы он не мешал после того, как данные были распределены, сгруппированы и вложены по CLIENT:

    library(tidyverse)
    
    df %>%
      spread(key = QST, value = VALUE, fill = 0) %>%
      select(-RESP_ID) %>%
      group_by(CLIENT) %>%
      nest()
    #> # A tibble: 2 x 2
    #>   CLIENT data             
    #>   <fct>  <list>           
    #> 1 A      <tibble [5 × 10]>
    #> 2 B      <tibble [5 × 10]>
    

    После этого создайте столбец линейных моделей. Передача quick = T в broom::tidy возвращает упрощенную версию таблицы диагностики модели; без установки этого параметра вы также получите стандартную ошибку, тестовую статистику и значение p для каждой переменной в модели.

    df %>%
      spread(key = QST, value = VALUE, fill = 0) %>%
      select(-RESP_ID) %>%
      group_by(CLIENT) %>%
      nest() %>%
      mutate(lm_mod = map(data, function(d) lm(Q2 ~ ., data = d))) %>%
      mutate(mod_tidy = map(lm_mod, broom::tidy, quick = T)) %>%
      unnest(mod_tidy) %>%
      head()
    #> # A tibble: 6 x 3
    #>   CLIENT term        estimate
    #>   <fct>  <chr>          <dbl>
    #> 1 A      (Intercept)    2.67 
    #> 2 A      Q1             0.333
    #> 3 A      Q10           NA    
    #> 4 A      Q3            -0.333
    #> 5 A      Q4            -1.   
    #> 6 A      Q5             1.
    
    10.05.2019
    Новые материалы

    Создание кнопочного меню с использованием HTML, CSS и JavaScript
    Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

    Внедрите OAuth в свои веб-приложения для повышения безопасности
    OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

    Классы в JavaScript
    class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

    Как свинг-трейдеры могут использовать ИИ для больших выигрышей
    По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

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

    Обзор: Машинное обучение: классификация
    Только что закончил третий курс курса 4 часть специализации по машинному обучению . Как и второй курс, он был посвящен низкоуровневой работе алгоритмов машинного обучения. Что касается..

    Разработка расширений Qlik Sense с qExt
    Использование современных инструментов веб-разработки для разработки крутых расширений Вы когда-нибудь хотели кнопку для установки переменной в приложении Qlik Sense? Когда-нибудь просили..