在R中根据另一列创建类别列

4

我有一些数据,每个观察值(行)都有一个唯一的id。根据id的第一个字母,观察值可以分为两组。我想要一个列/变量来标识这两个组。

下面的代码可以实现此功能。但我的问题是是否有更优雅的R语言方法来完成这个任务?

> df <- data.frame(id = c("C-1", "P-2", "P-3", "C-2"))
> df$tmp_id <- startsWith(as.character(df$id), "C-")
> df
   id tmp_id
1 C-1   TRUE
2 P-2  FALSE
3 P-3  FALSE
4 C-2   TRUE
> df$typ[df$tmp_id == TRUE] <- "C"
> df$typ[df$tmp_id == FALSE] <- "P"
> df$typ <- factor(df$typ, levels=c("C", "P"), labels=c("Cheese", "Pork"))
> df
   id tmp_id    typ
1 C-1   TRUE Cheese
2 P-2  FALSE   Pork
3 P-3  FALSE   Pork
4 C-2   TRUE Cheese
> df$tmp_id <- NULL
> df
   id    typ
1 C-1 Cheese
2 P-2   Pork
3 P-3   Pork
4 C-2 Cheese

我的问题的一个延伸是如果我有超过两个组怎么处理这种情况?例如: CheesePorkCandyChocolate

2个回答

2

一个简单的方法是创建一个命名向量,比如types,用作查找表将前缀与组链接起来。然后,您可以从id列中提取前缀,并索引查找向量以找到相应的组名:

df <- data.frame(id = c("C-1", "P-2", "P-3", "C-2"))

types <- c(C = "Cheese", P = "Pork")
df$typ <- types[substr(df$id, 1, 1)]

df
#>    id    typ
#> 1 C-1 Cheese
#> 2 P-2   Pork
#> 3 P-3   Pork
#> 4 C-2 Cheese

如果您想要添加额外的组,您只需要将更多的前缀-组映射添加到充当查找表的向量中即可:
df <- data.frame(id = c("Ch-1", "Po-2", "Po-3", "Ca-2"))

types <- c(Ca = "Candy", Ch = "Cheese", Po = "Pork")
df$typ <- types[substr(df$id, 1, 2)]

df
#>     id    typ
#> 1 Ch-1 Cheese
#> 2 Po-2   Pork
#> 3 Po-3   Pork
#> 4 Ca-2  Candy

如果您希望允许不同长度的前缀,则可能需要查看正则表达式以从id列中提取它们。
reprex包(v0.2.0)于2018-05-02创建。

第三行(types...)很有趣!我从未见过这样的语法。为什么可以不用引号写Ca?你有相关R文档基础部分的链接吗? - buhtz
但是 df$typcharacter 而不是 factor。这里只需添加这一行代码 df$typ <- factor(df$typ, levels=c("C", "P"), labels=c("Cheese", "Pork")) 或者有更加优雅的方式吗? ;) - buhtz
1
我从未真正考虑过c中的命名问题,但如果你为其提供参数名称,它们将用于创建结果向量的名称。我似乎找不到这种行为的文档。关于获取一个“factor”,最简单的方法是使用as.factordf $ typ <- as.factor(types [substr(df $ id,1,1)])。除非您希望因子级别按特定顺序排列,在这种情况下,像您建议的那样使用factor会是可行的方式。 - Mikko Marttila

1

dplyr包能够优雅地处理这个问题。我认为你需要一个名为flaggingflag的变量/列。它将告诉你哪些行符合某个条件,哪些不符合。以下代码将生成一个标记编码为1,用于所有在id列中以C开头的行。type列只是另一个标志,可以通过ifelse语句同样创建。

require(dplyr)

df <-  data.frame(id = c("C-1", "P-2", "P-3", "C-2")) # OP's dataset

df %>% 
  mutate(flag = ifelse(str_detect(id,'C'),1,0), # mutate adds columns
         type = ifelse(flag == 1,'Cheese','Pork')) 


# A tibble: 4 x 3
  id     flag type  
  <chr> <dbl> <chr> 
1 C- 1   1.00 Cheese
2 P- 2   0    Pork  
3 P- 3   0    Pork  
4 C- 4   1.00 Cheese

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接