【问题标题】:Detect a pattern in a column with R用 R 检测列中的模式
【发布时间】:2018-07-04 17:55:13
【问题描述】:

我试图计算一个人从一份工作转到另一份工作的次数。这可以在每次 Job 列具有此模式 1 -> 0 -> 1 时计算。

在这个例子中,它发生了一个旋转:

Person Job
  A     1
  A     0
  A     1
  A     1

在另一个例子中,B 也有一个轮换。

Person Job
  A     1
  A     0
  A     1
  A     1
  B     1
  B     0
  B     0 
  B     1

按人在新列“轮换”中衡量这种模式的好方法是什么?

    Person Job  Rotation
      A     1      0
      A     0      0
      A     1      1
      A     1      1
      B     1      0
      B     0      0
      B     0      0
      B     1      1

【问题讨论】:

  • 为什么是Rotation[4] == 1
  • 因为它是累积的。每行代表一个学期。这意味着,在 2 年内,A 人轮换了 1 次

标签: r dplyr tidyverse


【解决方案1】:

您可以使用正则表达式来捕获具有101 的组并将其计为 1。因此您可以使用 pattern="(?<=1)0+(?=1)" 其中对于所有零,检查它们是否以 1 开头并以 1 为后缀

library(tidyverse)
df%>%
   group_by(Person)%>%
   mutate(Rotation=str_count(accumulate(Job,str_c,collapse=""),"(?<=1)0+(?=1)"))
# A tibble: 12 x 3
# Groups:   Person [3]
   Person   Job Rotation
   <fct>  <int>    <int>
 1 A          1        0
 2 A          0        0
 3 A          1        1
 4 A          1        1
 5 B          1        0
 6 B          0        0
 7 B          0        0
 8 B          1        1
 9 C          0        0
10 C          1        0
11 C          0        0
12 C          1        1

【讨论】:

    【解决方案2】:

    一种解决方案是将lagdefault = 0 一起使用,并在值从0 变为1 时计算条件的累积和。只需从cumsum 中减去1 即可获得旋转。

    使用dplyr的解决方案可以是:

    library(dplyr)
    
    df %>% group_by(Person) %>%
      mutate(Rotation = cumsum(lag(Job, default = 0) == 0 & Job ==1) - 1) %>%
      as.data.frame()
    
    #   Person Job Rotation
    # 1      A   1        0
    # 2      A   0        0
    # 3      A   1        1
    # 4      A   1        1
    # 5      B   1        0
    # 6      B   0        0
    # 7      B   0        0
    # 8      B   1        1
    

    数据:

    df <- read.table(text ="
    Person Job
    A     1
    A     0
    A     1
    A     1
    B     1
    B     0
    B     0 
    B     1",
    header = TRUE, stringsAsFactors = FALSE)
    

    【讨论】:

      【解决方案3】:

      这是data.table的选项

      library(data.table)
      setDT(df)[, Rotation := +(grepl("101", do.call(paste0,
                             shift(Job, 0:.N, fill = 0)))), Person]
      df
      #    Person Job Rotation
      # 1:      A   1       0
      # 2:      A   0       0
      # 3:      A   1       1
      # 4:      A   1       1
      # 5:      B   1       0
      # 6:      B   0       0
      # 7:      B   0       0
      # 8:      B   1       0
      # 9:      C   0       0
      #10:      C   1       0
      #11:      C   0       0
      #12:      C   1       1
      

      base R 选项将是

      f1 <- function(x) Reduce(paste0, x, accumulate = TRUE)
      df$Rotation <- with(df, +grepl("101", ave(Job, Person, FUN = f1)))
      

      数据

      df <- data.frame(Person = rep(c("A", "B", "C"), each = 4L),
                       Job = as.integer(c(1,0,1,1,
                                          1,0,0,1,
                                          0,1,0,1)))
      

      【讨论】:

        【解决方案4】:

        我假设如果一个人开始失业, 他们得到的第一份工作不算轮换。 在这种情况下:

        library(dplyr)
        
        rotation <- function(x) {
            # this will have 1 when a person got a new job
            dif <- c(0L, diff(x))
            dif[dif < 0L] <- 0L
            if (x[1L] == 0L) {
                # unemployed at the beginning,
                # first job doesn't count as change from one to another
                dif[which.max(dif)] <- 0L
            }
            # return
            cumsum(dif)
        }
        
        df <- data.frame(Person = rep(c("A", "B", "C"), each = 4L),
                         Job = as.integer(c(1,0,1,1,
                                            1,0,0,1,
                                            0,1,0,1)))
        
        df %>%
            group_by(Person) %>%
            mutate(Rotation = rotation(Job))
        # A tibble: 12 x 3
        # Groups:   Person [3]
           Person   Job Rotation
           <fct>  <int>    <int>
         1 A          1        0
         2 A          0        0
         3 A          1        1
         4 A          1        1
         5 B          1        0
         6 B          0        0
         7 B          0        0
         8 B          1        1
         9 C          0        0
        10 C          1        0
        11 C          0        0
        12 C          1        1
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-02-05
          • 1970-01-01
          • 1970-01-01
          • 2020-07-12
          • 1970-01-01
          • 1970-01-01
          • 2020-07-29
          • 1970-01-01
          相关资源
          最近更新 更多