在一个实验中,人们有四个候选人可供选择;有时他们是男性,其他时候是女性。在下面的数据框中,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等于零。
这将需要我根据“响应”列的值查找特定列。
我该怎么做?
答案 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
这是基本概念,请使用相应的值选择列。然后将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)
答案 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())