Поиск определенного столбца в R в зависимости от другого столбца - PullRequest
0 голосов
/ 24 августа 2018

В эксперименте у людей было четыре кандидата на выбор; иногда они мужчины, а иногда женщины. В приведенном ниже кадре данных C1 означает «Кандидат 1», C2 означает «Кандидат 2» и т. Д. F обозначает женщину, а M обозначает мужчину. Ответ 1 означает, что человек выбрал С1, ответ 2 означает, что человек выбрал С2 и т. Д.

C1    C2    C3    C4    response
F     F     M     M     2
M     M     F     M     1

Я хочу новый столбец «ChooseFemale», который равен 1, если кандидат выбрал женщину-кандидата, и ноль в противном случае. Таким образом, первая строка должна иметь ChooseFemale, равный 1, а вторая строка должна иметь ChooseFemale, равный нулю.

Это потребует от меня поиска определенного столбца в зависимости от значения столбца «response».

Как я могу это сделать?

Ответы [ 6 ]

0 голосов
/ 24 августа 2018

Вы можете создать простую функцию, чтобы проверить, соответствует ли номер ответа «F», и затем применить его к каждой строке сразу.

A tidyverse подход:

library(tidyverse)

mydata <- data.frame(C1=sample(c("F","M"),10,replace = T),
                     C2=sample(c("F","M"),10,replace = T),
                     C3=sample(c("F","M"),10,replace = T),
                     C4=sample(c("F","M"),10,replace = T),
                     response=sample(c(1:4),10,replace = T),
                     stringsAsFactors = FALSE)

   C1 C2 C3 C4 response
1   M  M  M  M        1
2   F  F  F  M        4
3   M  F  M  M        2
4   F  M  M  F        2
5   M  M  M  F        1
6   M  F  M  F        4
7   M  M  M  F        3
8   M  M  M  M        2
9   M  F  M  M        3
10  F  F  M  F        4

Пользовательская функция для проверки соответствия ответа "F"

female_choice <- function(C1, C2, C3, C4, response) {

    c(C1, C2, C3, C4)[response] == "F"

}   

А затем просто используйте mutate() для изменения вашего фрейма данных и pmap(), чтобы использовать его строки, одну за другой, в качестве набора аргументов для female_choice()

mydata %>% 
    mutate(ChooseFemale = pmap_chr(., female_choice))

   C1 C2 C3 C4 response ChooseFemale
1   M  M  M  M        1        FALSE
2   F  F  F  M        4        FALSE
3   M  F  M  M        2         TRUE
4   F  M  M  F        2        FALSE
5   M  M  M  F        1        FALSE
6   M  F  M  F        4         TRUE
7   M  M  M  F        3        FALSE
8   M  M  M  M        2        FALSE
9   M  F  M  M        3        FALSE
10  F  F  M  F        4         TRUE
0 голосов
/ 24 августа 2018

Вот один из способов сделать это с помощью пакетов tidyverse.Как указано в вопросе, здесь учитывается как выбранный кандидат (C1-C4), так и пол кандидата (F / M):

# loading needed libraries
library(tidyverse)

# data
df <- utils::read.table(text = "C1    C2    C3    C4    response
                 F     F     M     M     2
                 M     M     F     M     1", header = TRUE) %>%
  tibble::as_data_frame(x = .) %>%
  tibble::rowid_to_column(.)

# manipulation
dplyr::full_join(
# creating dataframe with the new chooseFemale variable
  x = df %>%
    tidyr::gather(
      data = .,
      key = "candidate",
      value = "choice",
      C1:C4
    ) %>%
    dplyr::mutate(choice_new = paste("C", response, sep = "")) %>%
# creating the needed column by checking both the candidate chosen and 
# the sex of the candidate
    dplyr::mutate(chooseFemale = dplyr::case_when((choice_new == candidate) &
                                                    (choice == "F") ~ 1,
                                                  (choice_new == candidate) &
                                                    (choice == "M") ~ 0
    )) %>%
    dplyr::select(.data = ., -choice_new) %>%
    tidyr::spread(data = ., key = candidate, value = choice) %>%
    dplyr::filter(.data = ., !is.na(chooseFemale)) %>%
    dplyr::select(.data = ., -c(C1:C4)),
# original dataframe
  y = df,
  by = c("rowid", "response")
) %>% # removing the redundant row id
  dplyr::select(.data = ., -rowid) %>% # rearranging the columns 
  dplyr::select(.data = ., C1:C4, response, chooseFemale)

#> # A tibble: 2 x 6
#>   C1    C2    C3    C4    response chooseFemale
#>   <fct> <fct> <fct> <fct>    <int>        <dbl>
#> 1 F     F     M     M            2            1
#> 2 M     M     F     M            1            0

Создано в 2018-08-24 Представить пакет (v0.2.0.9000).

0 голосов
/ 24 августа 2018

Другое базовое решение R:

x <- df[["response"]]

df$ChooseFemale <- as.integer(df[cbind(seq_along(x), x)] == "F")
  C1 C2 C3 C4 response ChooseFemale
1  F  F  M  M        2            1
2  M  M  F  M        1            0

Данные:

Lines <- "C1    C2    C3    C4    response
F     F     M     M     2
M     M     F     M     1"

df <- read.table(text = Lines, header = TRUE, stringsAsFactors = FALSE)
0 голосов
/ 24 августа 2018
apply(df,1,function(x) ifelse(df[,as.numeric(x['response'])]=='F',1,0))[,1]
[1] 1 0

Вот основная идея, выберите столбец, используя значение в ответе. Затем используйте apply с MARGIN=1 для применения этой функции строка за строкой.

df[1,'response']
[1] 2

df[1,df[1,'response']]
[1] F
Levels: F M

данные

df <- read.table(text = "
  C1    C2    C3    C4    response
   F     F     M     M     2
   M     M     F     M     1
",header=T)
0 голосов
/ 24 августа 2018

Я дам ответ в формате тидыр.Ваши данные в "широком" формате.Это делает его очень читаемым человеком, но не обязательно машиночитаемым.Первый шаг к тому, чтобы сделать его более аккуратным, - преобразовать данные в длинный формат.Другими словами, давайте преобразуем данные, чтобы нам не приходилось выполнять вычисления по нескольким столбцам в одной строке.

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

library(dplyr)
library(tidyr)

df <- data.frame(C1 = c("F","M"),
           C2 = c("F","M"),
           C3 = c("M","F"),
           C4 = c("M","M"),
           stringsAsFactors = FALSE)
> df
  C1 C2 C3 C4
1  F  F  M  M
2  M  M  F  M

Давайте добавим поле «id», чтобы мы могли отслеживатькаждого уникального ряда.Это то же самое, что и номер строки ... но мы собираемся конвертировать широкие данные в длинные данные с разными номерами строк.Затем используйте команду collect для преобразования из широких данных в длинные.

df_long <- df %>%
  mutate(id = row_number(C1)) %>%
  gather(key = "key", value = "value",C1:C4)
> df_long
  id key value
1  1  C1     F
2  2  C1     M
3  1  C2     F
4  2  C2     M
5  1  C3     M
6  2  C3     F
7  1  C4     M
8  2  C4     M

Теперь можно использовать group_by() для группировки на основе переменных, выполнения суммирования и т. Д.

Для того, что вы просили, сгруппируйте по столбцу id, а затем выполните вычисления для группы.В этом случае мы возьмем сумму всех значений, которые являются "F".Затем мы разгруппируемся и вернемся к широко читаемому формату.

df_long %>%
  group_by(id) %>%
  mutate(response = sum(value=="F",na.rm=TRUE)) %>%
  ungroup()
> df_long
# A tibble: 8 x 4
     id key   value response
  <int> <chr> <chr>    <int>
1     1 C1    F            2
2     2 C1    M            1
3     1 C2    F            2
4     2 C2    M            1
5     1 C3    M            2
6     2 C3    F            1
7     1 C4    M            2
8     2 C4    M            1

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

df <- df_long %>%
  spread(key,value) 
> df
# A tibble: 2 x 6
     id response C1    C2    C3    C4   
  <int>    <int> <chr> <chr> <chr> <chr>
1     1        2 F     F     M     M    
2     2        1 M     M     F     M

Чтобы вернуть данные в том порядке, в котором они у вас были:

df <- df %>%
  select(-id) %>%
  select(C1:C4,everything())
> df
# A tibble: 2 x 5
  C1    C2    C3    C4    response
  <chr> <chr> <chr> <chr>    <int>
1 F     F     M     M            2
2 M     M     F     M            1

Конечно, вы можете использовать каналы, чтобы сделать все это водин шаг.

df <- df %>%
  mutate(id = row_number(C1)) %>%
  gather(key = "key", value = "value",C1:C4) %>%
  group_by(id) %>%
  mutate(response = sum(value=="F",na.rm=TRUE)) %>%
  ungroup() %>%
  spread(key,value) %>%
  select(-id) %>%
  select(C1:C4,everything())
0 голосов
/ 24 августа 2018
# create dataframe
my.df <- data.frame(c1=c('f','m'),
                    c2=c('f','m'),
                    c3=c('m','f'),
                    c4=c('m','m'),
                    resp=c(2, 1))

# add column
my.df$ChooseFemale <- NA

# loop over rows
for (row in 1:nrow(my.df)){

  # extract the column to check from response column
  col <- paste0('c', my.df$resp[row])

  # fill in new column
  my.df$ChooseFemale[row] <- ifelse(my.df[row, col]=='f', 1, 0)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...