根据每一行的值改变一个新列

问题描述 投票:0回答:2

我有以下玩具数据框。

toy.df <- data.frame(Name = c("group1", "group2", "group3", "group4", "group5", "group6", "group7"), 
                 col1 = c("pos", "neg", "NA", "pos","neg", "NA", "pos"),
                 col2 = c("pos", "pos", "NA", "pos","neg","NA", "neg"),
                 col3 = c("pos", "NA", "pos", "NA", "neg", "neg", "neg"))

我想改变一个新列来检查每行所有列的值。如果它们都是“pos”或“NA”则变异“pos”,如果它们都是“neg”或“NA”则变异“neg”,如果它们都是“pos”或“neg”或“NA”则变异“both” .

新栏目如下:

col4 <- c("pos", "both", "pos", "pos","neg", "neg","both")

这是最终的数据框:

 Name  col1 col2 col3 col4
group1  pos  pos  pos  pos
group2  neg  pos  NA  both
group3  NA   NA   pos  pos
group4  pos  pos   NA  pos
group5  neg  neg  neg  neg
group6  NA   NA   neg  neg
group7  pos  neg  neg both
r if-statement dplyr mutate rowwise
2个回答
2
投票

由于数据框中的“NA”是文字“NA”,我们需要通过

NA
将其转换为真正的缺失值
na_if
。然后使用
case_when
提供新列分配的条件。我们需要
rowwise
让它在每一行都起作用。
TRUE ~ "unknown"
中的最后一个
case_when
捕获
col1
col3
中除“pos”和“neg”之外的字符串。

我添加了两个条目来显示当所有行都是

NA
或列中有错字时的行为。

library(dplyr)

toy.df %>% 
  rowwise() %>%  
  mutate(across(everything(), ~na_if(.x, "NA")),
         col4 = case_when(all(is.na(c_across(col1:col3))) ~ NA,
                          all(c_across(col1:col3) == "pos", na.rm = T) ~ "pos",
                          all(c_across(col1:col3) == "neg", na.rm = T) ~ "neg",
                          all(c_across(col1:col3) %in% c("pos", "neg", NA)) ~ "both",
                          TRUE ~ "unknown")) %>% 
  ungroup()

# A tibble: 9 × 5
  Name   col1  col2  col3  col4   
  <chr>  <chr> <chr> <chr> <chr>  
1 group1 pos   pos   pos   pos    
2 group2 neg   pos   NA    both   
3 group3 NA    NA    pos   pos    
4 group4 pos   pos   NA    pos    
5 group5 neg   neg   neg   neg    
6 group6 NA    NA    neg   neg    
7 group7 pos   neg   neg   both   
8 group8 NA    NA    NA    NA     
9 group9 pos   pos   typo  unknown

数据

toy.df <- structure(list(Name = c("group1", "group2", "group3", "group4", 
"group5", "group6", "group7", "group8", "group9"), col1 = c("pos", 
"neg", "NA", "pos", "neg", "NA", "pos", NA, "pos"), col2 = c("pos", 
"pos", "NA", "pos", "neg", "NA", "neg", NA, "pos"), col3 = c("pos", 
"NA", "pos", "NA", "neg", "neg", "neg", NA, "typo")), class = "data.frame", row.names = c(NA, 
-9L))

0
投票

另一种方式:

toy.df$group6 <- apply(toy.df, 1, \(x) {
  val <- sort(unique(x[2:4]))
  if (val[1] == "NA") val = val[2:length(val)]
  if (length(val) == 2) {
    "both"
  } else if (val=="pos")
    "pos"
  else 
    "neg"
})
toy.df

出:

    Name col1 col2 col3 group6
1 group1  pos  pos  pos    pos
2 group2  neg  pos   NA   both
3 group3   NA   NA  pos    pos
4 group4  pos  pos   NA    pos
5 group5  neg  neg  neg    neg
6 group6   NA   NA  neg    neg
7 group7  pos  neg  neg   both
© www.soinside.com 2019 - 2024. All rights reserved.