根据另一列在R中查找特定列

时间:2018-08-24 14:41:48

标签: r dataframe

在一个实验中,人们有四个候选人可供选择;有时他们是男性,其他时候是女性。在下面的数据框中,C1表示候选人1,C2表示候选人2,依此类推。 F表示女性,而M表示男性。响应1表示该人选择了C1,响应2表示该人选择了C2,依此类推。

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

我想要一个新列“ ChooseFemale”,如果候选人选择了女性候选人,则该列等于1,否则为0。因此,第一行的ChooseFemale等于1,而第二行的ChooseFemale等于零。

这将需要我根据“响应”列的值查找特定列。

我该怎么做?

6 个答案:

答案 0 :(得分:2)

另一种基础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)

答案 1 :(得分:0)

# 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)
}

答案 2 :(得分:0)

apply(df,1,function(x) ifelse(df[,as.numeric(x['response'])]=='F',1,0))[,1]
[1] 1 0

这是基本概念,请使用相应的值选择列。然后将applyMARGIN=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)

答案 3 :(得分:0)

这是使用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

reprex package(v0.2.0.9000)于2018-08-24创建。

答案 4 :(得分:0)

您可以创建一个简单的函数来检查响应号是否与“ F”匹配,然后一次将其应用于每一行。

一种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

答案 5 :(得分:-1)

我将以tidyr格式提供答案。您的数据采用“宽”格式。这使得它非常易于人类阅读,但不一定是机器可读的。使其更整洁的第一步是将数据转换为长格式。换句话说,让我们变换数据,这样我们就不必在一行中的多个列之间进行计算。

整洁的格式允许您使用分组变量,创建摘要等。

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”字段,以便我们可以跟踪每个唯一行。这与行号相同...但是我们将把宽数据转换为具有不同行号的长数据。然后使用搜集将宽数据转换为长数据。

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())