Отфильтруйте и выберите набор данных на основе значения в строке - PullRequest
0 голосов
/ 22 октября 2019

Я посмотрел на dplyr, tidyr и даже на базу R, но я не могу понять, как разместить мои данные на основе значения строки.

Я пытался использовать dplyr filter() и select()функций, но поскольку gender, language и age находятся в столбце id, я не могу фильтровать, просто набрав data %>% filter(gender == 1).

У меня есть список из 50 оценщиков. Для примера здесь я покажу 5. У меня есть 183 строки, которые включают ответы оценщиков на каждый вопрос, а в трех последних строках есть демографические данные, такие как возраст, пол и то, является ли кто-то носителем или не носителем языка. Я проиллюстрирую здесь 6 строк в качестве примера.

То, что я пытаюсь сделать, - это найти способ подгруппировать мои данные в соответствии со значениями в возрасте, поле и языковых значениях. Допустим, я хочу выбрать все оценки для пола 1, или для языка 1, или для пола 1 И языка 1.

Спасибо.

Код:

data <- data.frame("id" = c(901,902,903,"age",
                                        "gender",
                                        "language"), 
                   "rater1" = c(7, 9, 9, 21, 1, 1),
                   "rater2" = c(9, 9, 9, 39, 2, 2),
                   "rater3" = c(9, 9, 9, 38, 2, 1),
                   "rater4" = c(9, 9, 9, 33, 2, 1),
                   "rater5" = c(2, 9, 9, 21, 2, 1))

Ответы [ 4 ]

3 голосов
/ 22 октября 2019

Чтобы отфильтровать данные по полу и другим интересующим нас переменным, нам нужно изменить порядок данных, чтобы они представляли собой столбцы, а не строки в столбце. Один из способов сделать это - использовать сбор и распространение. После изменения структуры вы можете использовать фильтрацию dplyr.

data <- data %>% 
  gather("Rater",rater1:rater5, value = "Value") %>% 
  spread(id, value = Value) %>% 
  filter(gender == 1)

1 голос
/ 22 октября 2019

Просто переверните его на бок. Обязательно сначала включите id в имена строк, а затем удалите id, чтобы предотвратить приведение типов. t также возвращает матрицу, поэтому вам нужно преобразовать данные обратно во фрейм данных с помощью as_tibble или as.data.frame:

library(dplyr)
data <- as_tibble(t(`rownames<-`(data, data$id)[-1]))

Теперь filter должен делать то, что вы ожидаете:

data %>% filter(gender == 1)

#### OUTPUT ####

# A tibble: 1 x 6
  `901` `902` `903`   age gender language
  <dbl> <dbl> <dbl> <dbl>  <dbl>    <dbl>
1     7     9     9    21      1        1
1 голос
/ 22 октября 2019

Я бы предложил работать с двумя фреймами данных: один (я называю demo) для демографической информации о оценщиках, 1 строка на каждого оценщика и один (я называю рейтинги) для оценок, которые дал каждый оценщик, 1 строка наОтвет:

library(tidyr)
library(dplyr)
demo = tail(data, 3)
ratings = head(data, -3)

demo_cols = demo$id
demo = data.frame(t(demo[-1]))
names(demo) = demo_cols
demo$rater = as.numeric(sub(pattern = "rater", replacement = "", rownames(demo)))
demo
#        age gender language rater
# rater1  21      1        1     1
# rater2  39      2        2     2
# rater3  38      2        1     3
# rater4  33      2        1     4
# rater5  21      2        1     5

ratings = tidyr::pivot_longer(ratings, cols = starts_with("rater"),
                              names_to = "rater", names_prefix = "rater") %>%
  mutate(rater = as.numeric(rater))
ratings
# # A tibble: 15 x 3
#    id    rater value
#    <fct> <dbl> <dbl>
#  1 901   1         7
#  2 901   2         9
#  3 901   3         9
#  4 901   4         9
#  5 901   5         2
#  6 902   1         9
#  ...

Затем, когда вы хотите сделать что-то вроде ", выберите все оценки для пола 1, или для языка 1, или для пола 1 И языка 1" , вывыполните простое filter из demo и присоединитесь к данным ratings, чтобы получить соответствующие записи:

demo %>% filter(gender == 1 & language == 1) %>%
  inner_join(ratings)
# Joining, by = "rater"
#   age gender language rater  id value
# 1  21      1        1     1 901     7
# 2  21      1        1     1 902     9
# 3  21      1        1     1 903     9

Вы также можете выполнить полное объединение ratings_with_demo = inner_join(ratings, demo) и напрямую отфильтровать этот фрейм данных. ,Но помните, что если вы сделаете это, каждая строка будет ответом . Если вы хотите сделать что-то вроде подсчета числа оценщиков на gender, фрейм данных demo будет намного более хорошим начальным местом.

1 голос
/ 22 октября 2019

Ну, я не уверен, хорошо ли это масштабируется для вашего варианта использования, но вы могли бы выполнить базовую индексацию:

# data
x <- data.frame("id" = c(901,902,903,"age","gender","language"), 
                   "rater1" = c(7, 9, 9, 21, 1, 1),
                   "rater2" = c(9, 9, 9, 39, 2, 2),
                   "rater3" = c(9, 9, 9, 38, 2, 1),
                   "rater4" = c(9, 9, 9, 33, 2, 1),
                   "rater5" = c(2, 9, 9, 21, 2, 1))

# ensure id is character and not factor
x$id <- as.character(x$id)

# select all raters whose gender or language is 1
x[, c(TRUE, x[x$id == "gender", -1] == 1) |
    c(TRUE, x[x$id == "language", -1] == 1) ]

TRUE гарантирует, что столбец id сохраняется в любом случае, а -1 гарантирует, что логический вектор имеет желаемую длину (количество столбцов).

...