当具有不同的字符串长度时,R将字符串拆分为多列,dplyr

R split a character string into multiple columns when have different string lengths, dplyr

我有动物追踪数据,随着时间的推移遇到每只动物,并且每次遇到的性别都被记录下来。共有三种类型的遭遇(类型 1、类型 2 和类型 3)。每行代表一种动物,每次相遇都被归类为 M(雄性)或 F(雌性)。类型中的每个字符代表一次遭遇(例如 MMMM 是一种动物,出现四次,每次都记录为男性)。

示例数据:

animal.ID    type1         type2       type3
1            MMMMMMM       M           M
2            MFMM          M           M
3            FFM           F           F
4            FFFFFFFFF     F           F  
5            MM            M           M

我想知道每只动物的性别(雄性或雌性)记录是否一致。

我想制作这样的东西,其中一列表示性别是否始终如一地记录(1)或不一致(0)。

animal.ID    type1         type2       type3    consistent
1            MMMMMMM       M           M         1
2            MFMM          M           M         0
3            FFM           F           F         0
4            FFFFFFFFF     F           F         1
5            MM            M           M         1

我可以使用 if_else 获取 type2 和 type3 数据的 'consistent' 列:

df %>%
   mutate(consistent = if_else(type2 == type3), 1, 0))

但是,我不能包含 type1 数据,因为它在每个字符串中有多个字符,而且每个字符串中的字符数不同。

一种方法是使用 str_split 将 type1 拆分为多列,但是,鉴于每个字符串中的字符数不同,我不知道该怎么做。

一种方法可能是使用 strsplitunlist,检查所有字符是否等于 type2(除了检查 type2 是否等于 type3).

df %>%
  rowwise() %>%
  mutate(consistent = ifelse(type2 == type3 & all(unlist(strsplit(type1, "")) == type2), 1, 0))

输出

# A tibble: 5 x 5
  animal.ID type1     type2 type3 consistent
      <int> <chr>     <chr> <chr>      <dbl>
1         1 MMMMMMM   M     M              1
2         2 MFMM      M     M              0
3         3 FFM       F     F              0
4         4 FFFFFFFFF F     F              1
5         5 MM        M     M              1

我们可以使用charToRaw得到type1的"raw"表示,如果它们都相同则赋值1。

df$consistent <- +(sapply(df$type1, function(x) length(unique(charToRaw(x)))) ==1)

使用dplyr,我们可以使用与以下相同的逻辑:

library(dplyr)

df %>%
  rowwise() %>%
  mutate(consistent = +(n_distinct(charToRaw(type1)) == 1))


#  animal.ID type1     type2 type3 consistent
#      <int> <chr>     <chr> <chr>      <int>
#1         1 MMMMMMM   M     M              1
#2         2 MFMM      M     M              0
#3         3 FFM       F     F              0
#4         4 FFFFFFFFF F     F              1
#5         5 MM        M     M              1

数据

df <- structure(list(animal.ID = 1:5, type1 = c("MMMMMMM", "MFMM", 
"FFM", "FFFFFFFFF", "MM"), type2 = c("M", "M", "F", "F", "M"), 
type3 = c("M", "M", "F", "F", "M")), class = "data.frame", row.names = c(NA, -5L))

另一个使用逻辑的解决方案@Ronak Shah

library(tidyverse)
df %>% 
      unite("all_type", starts_with("type"), sep = "", remove = F) %>% 
      mutate(consistent = map(strsplit(all_type, ""), ~ +(n_distinct(.x) == 1)))