如何遍历列,检查任何列中是不是存在特定值,改变新列并输入 1 如果存在,如果不存在则输入 0?

Posted

技术标签:

【中文标题】如何遍历列,检查任何列中是不是存在特定值,改变新列并输入 1 如果存在,如果不存在则输入 0?【英文标题】:How to loop through columns, check if a particular value exists in any of the columns, mutate a new column and enter 1 if it exists, 0 if not?如何遍历列,检查任何列中是否存在特定值,改变新列并输入 1 如果存在,如果不存在则输入 0? 【发布时间】:2020-01-19 15:00:48 【问题描述】:

我正在做一个研究项目,其中一个表格的输入方式还不太适合分析,所以我正在尝试重新组织它。目前,每一行是一个考生,每一列是他们答错的问题,按升序输入。因此,对于第一行,第一列、第二列和第三列的条目可能分别为“Q1”“Q3”“Q9”等。总共有 25 个问题。

我的目标是重新组织数据,以便每个问题都有一个列。如果应试者正确回答了问题,则相应列的条目为 1,否则为 0。

有一种蛮力的方式似乎可行。可以单独改变每一列并检查每一列中的每个值。但是,有 25 个问题,而且所有这些打字似乎效率极低,所以我怀疑一定有更好的方法。

蛮力代码看起来像:

df %>%
  mutate(Q3 == ifelse(col1 == "Q3" | col2 == "Q3" | col3 == "Q3", 0, 1))

这里 col1, col2, col3 都是可能包含 Q3 的列,这可能是考生答错的问题。如果有任何一个,我们输入 0。否则,我们输入 1。

25 个问题,代码太长了。

编辑:数据框的示例如下所示。

sample <- "ID   Col1  Col2  Col3  Col4
1          100   Q1     
2          101   Q3    Q4
3          102   Q2    Q3    Q4   
4          103   
5          104   Q4
6          105   Q1    Q2    Q3    Q4 "

想要的输出如下:

sample <- "ID    Q1    Q2    Q3    Q4
1          100   0     1     1     1
2          101   1     1     0     0
3          102   1     0     0     0   
4          103   1     1     1     1
5          104   1     1     1     0 
6          105   0     0     0     0 "

【问题讨论】:

您能否分享输入数据的样本(不是所有列,也不是所有行)以及基于此的所需输出。阅读此主题以了解有关通过可重复示例提问的更多信息:***.com/questions/5963269/… 【参考方案1】:

这是我的解决方案 - 将数据从宽变为长并再次返回

s <- reshape2::melt(sample, id.vars = "ID", value.name = "Q")
s$variable <- 1
s <- subset(s, complete.cases(s))
s <- reshape(s, idvar = "ID", timevar = "Q", direction = "wide")
s <- apply(s, 2, function(x) ifelse(is.na(x), 0, x))

【讨论】:

【参考方案2】:

1) 假设DF 可重现地显示在最后的注释中,使用sapply 创建指标矩阵,然后将cbind 它添加到ID 列。最后让名字更好听。不使用任何包。

ques <- function(i) paste0("Q", 1:25) %in% unlist(DF[i, -1])
DFout <- cbind(DF[1], +t(sapply(1:nrow(DF), ques)))
names(DFout)[-1] <- paste0("Q", names(DFout[-1]))

前 5 列是:

> DFout[1:5]

   ID Q1 Q2 Q3 Q4
1 100  1  0  0  0
2 101  0  0  1  1
3 102  0  1  1  1
4 103  0  0  0  0
5 104  0  0  0  1
6 105  1  1  1  1

2) 另一种可能性是将输入转换为长格式,然后使用xtabs 从中创建表格。

library(dplyr)
library(tidyr)

tab <- DF %>% 
  gather(key, Question, -ID) %>%
  filter(nzchar(Question)) %>%
  mutate(Question = factor(Question, paste0("Q", 1:25))) %>%
  xtabs(~ ID + Question, .)

给这张桌子。我们显示前 5 列:

> tab[, 1:5]

     Question
ID    Q1 Q2 Q3 Q4
  100  1  0  0  0
  101  0  0  1  1
  102  0  1  1  1
  104  0  0  0  1
  105  1  1  1  1

如果结果是数据框很重要,则添加:

library(tibble)

tab %>% 
  as.data.frame.matrix %>% 
  rownames_to_column(var = "ID")    

注意

sample <- "rows ID   Col1  Col2  Col3  Col4
1          100   Q1     
2          101   Q3    Q4
3          102   Q2    Q3    Q4   
4          103   
5          104   Q4
6          105   Q1    Q2    Q3    Q4"
DF <- read.table(text = sample, header = TRUE, fill = TRUE, as.is = TRUE,
  strip.white = TRUE)[-1]

【讨论】:

【参考方案3】:

@G.Grothendieck 提供了一个非常好的解决方案。这是该答案的变体,即使每个学生都正确回答,它也会为测试中的每个问题产生一个值。诚然,它有点不那么优雅。另请注意,我用缺失值而不是空字符串构造数据,因此过滤器有点不同

dat <- data.frame(ID = c(100:105), 
                  Col1 = c("Q1", "Q3", "Q2", NA, "Q4", "Q1"), 
                  Col2 = c(NA, "Q4", "Q3", NA, NA, "Q2"), 
                  Col3 = c(NA, NA, "Q4", NA, NA, "Q3"), 
                  Col4 = c(NA, NA, NA, NA, NA, "Q4"), 
                  stringsAsFactors = FALSE)

dat %>%
  gather(key = col, val = wrong, -ID) %>%
  select(-col) %>%
  mutate(tmp = 1) %>%
  complete(wrong = paste0("Q", 1:25)) %>%
  filter(!is.na(wrong)) %>%
  spread(wrong, tmp, fill = 0) %>%
  select(ID, paste0("Q", 1:25)) %>%
  filter(!is.na(ID)) %>%
  data.frame

【讨论】:

【参考方案4】:

这是一种类似于其他方法的 convert-to-long-first 方法,但使用 data.table

library(data.table)
setDT(df)

dcast(melt(df, 'ID'), ID ~ value, fun.aggregate = length)[, V1 := NULL][]
#     ID Q1 Q2 Q3 Q4
# 1: 100  1  0  0  0
# 2: 101  0  0  1  1
# 3: 102  0  1  1  1
# 4: 104  0  0  0  1
# 5: 105  1  1  1  1

【讨论】:

【参考方案5】:

这将是一种使用简单 for 循环的方法。

让我们从上面获取这些数据:

sample <- "rows ID   Col1  Col2  Col3  Col4
1          100   Q1     
2          101   Q3    Q4
3          102   Q2    Q3    Q4   
4          103   
5          104   Q4
6          105   Q1    Q2    Q3    Q4"
DF <- read.table(text = sample, header = TRUE, fill = TRUE, as.is = TRUE,
                 strip.white = TRUE)[-1]

这是方法。它填充现有数据框以再次检查重新编码是否顺利:

vars <- paste0("Q", 1:4)

for (i in vars)
  DF[i] = rowSums(ifelse(DF[, grep( "Col", names(DF))]==i, 1, 0))
  

之后可以删除不需要的列:

DF <- DF[, -grep( "Col", names(DF))]

【讨论】:

以上是关于如何遍历列,检查任何列中是不是存在特定值,改变新列并输入 1 如果存在,如果不存在则输入 0?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查sql的第一列或第二列中是不是存在一个特定值?

检查VBA中的列中是不是存在值

数据框行和列是不是包含字符串?如果是这样,则在新列中返回该字符串

如何检查 var 是不是存在于数据库列中,如果不存在则不执行任何操作

Pandas:使用 apply 将特定列中的行值复制到新列中

如何遍历列并检查该值是不是与下一个值匹配然后追加?