>

매월 45 개월 동안 개인의 고용 상태를 기록하는 종단 데이터 집합이 있습니다. 이 데이터 세트에 추가 할 두 개의 변수를 만들 수 있기를 원합니다. 1) 각 사람이 "실업"을 보낸 전체 기간 2) 실업 주문의 수

이상적으로도 주문을 방해하지 않고 NA를 건너 뛸 수 있습니다

간단하게하기 위해 예제 데이터 세트를 만들었습니다 :


    ID <- c(1:10, 1:10, 1:10)
    date <- c("2006-09-01", "2006-09-01", "2006-09-01", "2006-09-01", "2006-09-01", "2006-09-01", "2006-09-01", 
              "2006-09-01", "2006-09-01", "2006-09-01", "2006-10-01", "2006-10-01", "2006-10-01", "2006-10-01", 
              "2006-10-01", "2006-10-01", "2006-10-01", "2006-10-01", "2006-10-01", "2006-10-01", "2006-11-01", 
              "2006-11-01", "2006-11-01", "2006-11-01", "2006-11-01", "2006-11-01", "2006-11-01", "2006-11-01", 
              "2006-11-01", "2006-11-01")
    act <- c("Unemployed", "Employment", "Education", "Education", "Education", "Education", "Education", 
             "Education", "Education", "Unemployed", "Education", "Unemployed", "Unemployed", "Unemployed", 
             "Education", "Education", "Employment", "Education", "Education", "NA", "Unemployed", 
             "Unemployed", "NA", "Unemployed", "Education", "Employment", "Employment", "NA", "Education", 
             "Unemployed")
    df <- data.frame(ID, date, act)
    df[order(ID),]
       ID       date        act
    1   1 2006-09-01 Unemployed
    11  1 2006-10-01  Education
    21  1 2006-11-01 Unemployed
    2   2 2006-09-01 Employment
    12  2 2006-10-01 Unemployed
    22  2 2006-11-01 Unemployed
    3   3 2006-09-01  Education
    13  3 2006-10-01 Unemployed
    23  3 2006-11-01         NA
    4   4 2006-09-01  Education
    14  4 2006-10-01 Unemployed
    24  4 2006-11-01 Unemployed
    5   5 2006-09-01  Education
    15  5 2006-10-01  Education
    25  5 2006-11-01  Education
    6   6 2006-09-01  Education
    16  6 2006-10-01  Education
    26  6 2006-11-01 Employment
    7   7 2006-09-01  Education
    17  7 2006-10-01 Employment
    27  7 2006-11-01 Employment
    8   8 2006-09-01  Education
    18  8 2006-10-01  Education
    28  8 2006-11-01         NA
    9   9 2006-09-01  Education
    19  9 2006-10-01  Education
    29  9 2006-11-01  Education
    10 10 2006-09-01 Unemployed
    20 10 2006-10-01         NA
    30 10 2006-11-01 Unemployed


롤랜드가 제안한 R의 기간 계산 솔루션을 시도했지만 확실하지 않습니다. ID별로 결과를 제공하고 NA를 처리하도록 조정하는 방법


    library(data.table)
    setDT(df)
    df[, date := as.POSIXct(date, format = "%Y-%m-%d", tz = "GMT")]
    glimpse(df)
    df$act <- ifelse(df$act == "Unemployed",1,-1)
    df[, run := cumsum(c(1, diff(act) != 0))]
    df1 <- df[, list(act = unique(act), 
                               duration = difftime(max(date), min(date), unit = "weeks")), 
                        by = run]
    df1
        run act duration
     1:   1   1  0 weeks
     2:   2  -1  0 weeks
     3:   3   1  0 weeks
     4:   4  -1  0 weeks
     5:   5   1  0 weeks
     6:   6  -1  0 weeks
     7:   7   1  0 weeks
     8:   8  -1  0 weeks
     9:   9   1  0 weeks
    10:  10  -1  0 weeks
    11:  11   1  0 weeks


내가 겪고있는 것은 이것을 달성하는 것입니다 (여기 기간은 몇 개월이지만 몇 주 또는 며칠이 될 수 있습니다) :

   ID spell_count duration
1    1           2        2
2    2           1        2
3    3           1        1
...
10  10           1        2

링크/문학/예제에 대한 도움을 주시면 대단히 감사하겠습니다.

감사합니다.

  • 답변 # 1

    첫 번째 코드 블록 만 사용하고 있으며 전체 기간 동안 다음을 수행합니다.

    
        library(data.table)
        setDT(df)
        df_duration = df[act=="Unemployed",.(duration = .N),by = ID]
    
    
    

    실업 주문의 수는 조금 까다 롭다 :

    
        df_spell_count = df[order(ID,date)]
        df_spell_count <- df_spell_count[!(is.na(act)|act=="NA")]
        df_spell_count[,previous_act := shift(act,1),by = ID]
        df_spell_count<-df_spell_count[act =="Unemployed" & (previous_act!="Unemployed" | is.na(previous_act))]
        df_spell_count<-df_spell_count[,.(spell_count =.N),by = ID]
    
    
    

    두 가지를 병합하려면 다음을 수행하십시오.

    df_stats <- merge(df_duration,df_spell_count, by = "ID", all.x = TRUE,all.y = TRUE)
    
    

    이 문서에는 실업 기간이없는 사용자를위한 행이 포함되어 있지 않아야합니다.

  • 답변 # 2

    tidyverse 패키지  변수 (또는 그 이상)로 그룹화하고 매우 쉽게 요약 할 수 있습니다.

    데이터를 집계하기 전에 date 열을 강제 실행합니다.   Date 수업  문자열 "NA" 를 바꿉니다.  실제 결 측값으로, NA .

    library(tidyverse)
    is.na(df$act) <- df$act == "NA"
    df$date <- as.Date(df$date)
    df %>%
      group_by(ID, act) %>%
      summarise(spell_count = sum(act == "Unemployed", na.rm = TRUE),
                duration = difftime(last(date), first(date), units = "weeks")) %>%
      filter(act == "Unemployed") %>%
      select(-act)
    ## A tibble: 5 x 3
    ## Groups:   ID [5]
    #     ID spell_count duration      
    #  <int>       <int> <time>        
    #1     1           2 8.714286 weeks
    #2     2           2 4.428571 weeks
    #3     3           1 0.000000 weeks
    #4     4           2 4.428571 weeks
    #5    10           2 8.714286 weeks
    
    

    위의 코드는 하나 이상의 act == "Unemployed" 가있는 행만 제공합니다.
    모든 행을 원하면 다음 기본 R 솔루션이 수행합니다.

    res <- lapply(split(df, df$ID), function(DF){
      i <- DF$act == "Unemployed"
      if(any(i, na.rm = TRUE))
        duration <- difftime(max(DF$date[i], na.rm = TRUE), min(DF$date[i], na.rm = TRUE), units = "weeks")
      else
        duration <- 0
      spell_count <- sum(i, na.rm = TRUE)
      data.frame(ID = DF$ID[1], spell_count, duration)
    })
    res <- do.call(rbind, res)
    row.names(res) <- NULL
    res
    #   ID spell_count       duration
    #1   1           2 8.714286 weeks
    #2   2           2 4.428571 weeks
    #3   3           1 0.000000 weeks
    #4   4           2 4.428571 weeks
    #5   5           0 0.000000 weeks
    #6   6           0 0.000000 weeks
    #7   7           0 0.000000 weeks
    #8   8           0 0.000000 weeks
    #9   9           0 0.000000 weeks
    #10 10           2 8.714286 weeks
    
    

  • 답변 # 3

    여기서 tidyverse를 사용하는 또 다른 시도가 있습니다. "주문"에 대한 데이터는 패널 데이터의 일반적인 변형입니다. tidyverse 접근법에서 OP의 원래 코드에서 "실행"변수와 같은 철자 변수를 생성하는 것이 트릭이라고 생각합니다.

    # libraries
    library(tidyverse)
    library(zoo)
    library(lubridate)
    # example dataset
    ID <- c(1:10, 1:10, 1:10)
    date <- c("2006-09-01", "2006-09-01", "2006-09-01", "2006-09-01", "2006-09-01", "2006-09-01", "2006-09-01", 
              "2006-09-01", "2006-09-01", "2006-09-01", "2006-10-01", "2006-10-01", "2006-10-01", "2006-10-01", 
              "2006-10-01", "2006-10-01", "2006-10-01", "2006-10-01", "2006-10-01", "2006-10-01", "2006-11-01", 
              "2006-11-01", "2006-11-01", "2006-11-01", "2006-11-01", "2006-11-01", "2006-11-01", "2006-11-01", 
              "2006-11-01", "2006-11-01")
    act <- c("Unemployed", "Employment", "Education", "Education", "Education", "Education", "Education", 
             "Education", "Education", "Unemployed", "Education", "Unemployed", "Unemployed", "Unemployed", 
             "Education", "Education", "Employment", "Education", "Education", "NA", "Unemployed", 
             "Unemployed", "NA", "Unemployed", "Education", "Employment", "Employment", "NA", "Education", 
             "Unemployed")
    df <- data.frame(ID, date, act)
    df[order(ID),]
    # convert types of some variables (in particular use zoo::yearmon instead of date, since these are actually yearmonth combos)
    df$act <- as.character(df$act)
    df$date <- lubridate::ymd(df$date)
    df$yearmon <- zoo::as.yearmon(df$date)
    df$act <- ifelse(df$act=='NA',NA,df$act)
    
    # construct "act2", which is act, except when an NA is surrounded by the SAME act before and after, it is replaced with that same act
    # e.g. Unemployed NA Unemployed -> Unemployed Unemployed Unemployed
    # e.g. Education NA Unemployed -> stays the same
    # (see note at the end of this discussion for more details on this)
    df <- df %>% arrange(ID,date)
    df <- df %>% group_by(ID) %>% mutate(
      act2 = ifelse(is.na(act) & (lag(act)==lead(act)), lead(act), act)
    )
    # create "spell" variable, which is like the "run" variable in the example code
    # within ID this identifies the spell that is currently taken place 
    # --- this is the most important part of the code ---
    df <- df %>% group_by(ID) %>% mutate(
      spell = cumsum(coalesce(is.na(act2) | act2!=lag(act2),FALSE)) + 1
    )
    # add yearmonth + 1 month, in order to do duration calculations
    # (I'm again exploiting the fact that your data is monthly. if this were not true, this variable could be lead(date), within ID. but then we'd have to figure out how to deal with ends of the panel, where lead(date) is NA)
    df$yearmonplusmonth <- df$yearmon + (1/12)
    # construct a dataset of ID-spell combinations
    spells <- df %>% group_by(ID,spell) %>% summarize(
      spelltype = first(act2),
      duration = (max(yearmonplusmonth) - min(yearmon))*12
    )
    # construct a dataset at the ID level, with desired summaries of spells
    spellsummary <- spells %>% group_by(ID,spelltype) %>% summarize(
      spell_count = n(),
      duration = sum(duration)
    ) 
    # if there are no spells of a given spelltype, it doesn't appear in spellsummary
    # we need to fill out spellsummary with zeroes in ID-spelltype cases where there are no spells:
    temp <- expand.grid(ID = unique(spellsummary$ID), spelltype = unique(spellsummary$spelltype))
    spellsummary <- full_join(spellsummary,temp,by=c('ID','spelltype'))
    spellsummary <- spellsummary %>% mutate_at(vars(spell_count,duration),funs(coalesce(as.numeric(.),0)))
    spellsummary <- spellsummary %>% mutate_at(vars(spell_count,duration),funs(round(.,0)))
    spellsummary <- spellsummary %>% arrange(ID,spelltype)
    # finally, we just want Unemployed spelltype summaries by ID:
    spellsummary %>% filter(spelltype=='Unemployed')
    # A tibble: 10 x 4
    # Groups:   ID [10]
    # ID spelltype  spell_count duration
    # <int> <chr>            <dbl>    <dbl>
    # 1     1 Unemployed           2        2
    # 2     2 Unemployed           1        2
    # 3     3 Unemployed           1        1
    # 4     4 Unemployed           1        2
    # 5     5 Unemployed           0        0
    # 6     6 Unemployed           0        0
    # 7     7 Unemployed           0        0
    # 8     8 Unemployed           0        0
    # 9     9 Unemployed           0        0
    # 10    10 Unemployed           1        3
    
    

    참고 : 원하는 OP 출력에서 ​​2가 아니라 마지막 행에서 3을 얻습니다. 이유는 unemp NA Unemp가 spell_count의 목적과 기간의 목적 모두에 대해 Unemp Unemp Unemp라고 가정하기 때문입니다. OP는 spell_count의 경우이지만 지속 기간이 아닌 경우를 원합니다. 이를 달성하기위한 한 가지 방법은 기간 계산에 "act"변수를 사용하고 spell_count 계산에 "act2"변수를 사용하는 것입니다. 나는 이것을 독자에게 맡깁니다.

관련 자료

  • 이전 python - "initialize_app '기본 Firebase 앱이 이미 존재합니다'Cloud functions pub sub
  • 다음 Mysql 57의 JSON_OBJECT 기능