ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 수면 데이터로 나의 잠 시간 알아보기
    아이디어 2021. 6. 13. 19:17

     

     이번 시간에는 저의 수면 데이터를 통해 저의 잠 시간을 알아보도록 하겠습니다. 저의 수면 데이터는 작년 1월 7일부터 12월 31일까지 기록한 데이터입니다. 세바시 유튜브 채널에서 아주대학교 심리학과 김경일 교수님의 한국인이 놓치고 사는 숫자라는 강연 영상을 보고 저의 잠 시간을 알아보기 위해 작년 한해 동안 기록했답니다.

    library(dplyr)
    library(ggplot2)
    
    df <- readr::read_csv('sleep.csv')

     

     먼저 데이터를 가져와서 한번 살펴볼까요

    df %>% head(10)
    ## # A tibble: 10 x 5
    ##    date        hour minute nap   tossNturn
    ##    <date>     <dbl>  <dbl> <lgl> <lgl>    
    ##  1 2020-01-01    NA     NA NA    NA       
    ##  2 2020-01-02    NA     NA NA    NA       
    ##  3 2020-01-03    NA     NA NA    NA       
    ##  4 2020-01-04    NA     NA NA    NA       
    ##  5 2020-01-05    NA     NA NA    NA       
    ##  6 2020-01-06    NA     NA NA    NA       
    ##  7 2020-01-07     7     NA NA    NA       
    ##  8 2020-01-08     9     30 NA    NA       
    ##  9 2020-01-09     7     30 NA    NA       
    ## 10 2020-01-10     8     30 NA    NA

     데이터는 1월 7일부터 값이 들어가 있습니다. 전체 잠 시간이 hourminute 변수에 시, 분 단위로 쪼개져 들어가 있고, 추가로 낮잠을 잤는지 여부를 묻는 nap, 잠들기 전 뒤척임이 있었는지 여부를 묻는 tossNturn 변수가 있습니다.

    str(lapply(df, unique))
    ## List of 5
    ##  $ date     : Date[1:366], format: "2020-01-01" "2020-01-02" ...
    ##  $ hour     : num [1:10] NA 7 9 8 11 5 6 0 10 2
    ##  $ minute   : num [1:2] NA 30
    ##  $ nap      : logi [1:2] NA TRUE
    ##  $ tossNturn: logi [1:2] NA TRUE

     str을 살펴보면 다음과 같이 나오네요. 시간 분포는 2시간에서 11시간..까지 정도껏 다양하게 분포되어 있고, 30분 단위로 기록이 되어 있는 걸 확인할 수 있습니다. hour에는 NA값이 1월 6일까지만 있는게 전부고, minute에는 0값이 NA값으로 들어가있습니다. 한편 naptossNturn은 logical 변수인데, 둘다 FALSE값 대신 NA값이 들어가 있네요. NA값이 많아서 정리를 해줘야겠습니다. 먼저 시간 기록이 없는 1월 6일까지는 살펴볼 데이터가 없으니 제거하고

    df <- df %>% 
      filter(!is.na(hour))

     나머지 NA값에 0을 넣어줍니다.

    df <- df %>% replace(is.na(.), 00)

     그리고 table로 보면 깔끔하게 NA값이 정리된 걸 확인할 수 있습니다.

    table(is.na(df))
    ## 
    ## FALSE 
    ##  1800

     이 때 logical 변수에 NA값을 0으로 넣었는데 잘못 넣은게 아닐까 생각할 수도 있지만 logical에서 0은 FALSE로 받아주기 때문에 알아서 FALSE로 치환해준답니다.

    str(lapply(df, unique))
    ## List of 5
    ##  $ date     : Date[1:360], format: "2020-01-07" "2020-01-08" ...
    ##  $ hour     : num [1:9] 7 9 8 11 5 6 0 10 2
    ##  $ minute   : num [1:2] 0 30
    ##  $ nap      : logi [1:2] FALSE TRUE
    ##  $ tossNturn: logi [1:2] FALSE TRUE

     그래프를 그리기 위해 hour, minute으로 쪼개진 시간 변수를 하나의 변수로 합쳐보겠습니다. 포직스 프레임의 시간 정보로 바꿔서 HH:MM 형태로 저장하는 time 변수를 만들었습니다.

    df <- df %>% 
      mutate(time = format(as.POSIXct(paste0(hour, ':', minute), format = '%H:%M'), '%H:%M')) %>% 
      select(-c(hour, minute))

     그리고 히스토그램을 그려 제 잠 시간을 보겠습니다.

    # 히스토그램 
    df %>% 
      ggplot(aes(x = time)) +
      geom_histogram(stat = 'count') +
      theme_minimal()

    x축이 연속이 아니라는 점 주의해주세요.

     

     슥 보면 8시간 반이 가장 많습니다. 하지만 잠들기까지 걸리는 딜레이 시간까지 계산하면 얘기가 다를 수 있습니다. 잠들기 전 시간이 12시라면, 잠들기 시작한 시간을 12시로 측정했습니다. 중간에 화장실을 가기 위해 일어나거나 잠깐 딴 생각을 하느라 잠 못 든 시간은 계산이 안됐습니다. tossNturn 변수엔 그런 게 전부 반영되어 있지 않아요. tossNturn은 조금 심하게 잠에 들지 못한 경우, 예를 들어 1시에 잠자리에 들었는데 2~3시까지 잠을 못 잤다, 그러면 TRUE로 기입했습니다. 거의 불면증 같은 느낌이죠.

     따라서 실제 시간을 계산해보면 8시간 전후에 집중된 모습이라고 볼 수 있습니다. 개인적으로 컨디션 정도를 측정한 것도 있었는데 8시간 잤을 때 가장 컨디션 좋은 날이 많아서, 제 잠 시간을 8시간으로 판단할 수 있겠네요. 데이터에 컨디션 정도를 측정한 변수가 없는건 데이터가 3월까지 밖에 없어서 넣지 않았습니다.

     그럼 다른 변수들과 함께 잠 시간을 살펴보아요.

    # 낮잠을 잔 날
    df %>% 
      filter(nap == TRUE) %>% 
      ggplot(aes(x = time)) +
      geom_histogram(stat = 'count') +
      theme_minimal()

     대부분 8시간보다 못 잤을 때 낮잠을 자는 모습을 확인할 수 있습니다. 잠 시간이 8시간이라는 판단에 근거가 될 수 있겠네요.

    # 낮잠 잔 다음날
    df %>% 
      mutate(after_nap = ifelse(lag(nap) == TRUE, TRUE, FALSE)) %>% 
      filter(after_nap == TRUE) %>% 
      ggplot(aes(x = time)) +
      geom_histogram(stat = 'count') +
      theme_minimal()

     낮잠을 자고나면 다음날 수면 시간은 안정적으로 8시간에 몰리는 모습을 확인할 수 있습니다. 물론 날짜가 11일 밖에 안 되지만요.

    # 뒤척인 날
    df %>% 
      filter(tossNturn == TRUE) %>% 
      ggplot(aes(x = time)) +
      geom_histogram(stat = 'count') +
      theme_minimal()

     뒤척임이 있던 날 수면 데이터를 보면 수면 시간이 정확히 기재된 것처럼 보이지 않습니다. 그 이유는 간단한데, 뒤척이느라 잠드는 시간을 제대로 확인하지 못했기 때문입니다. 예를 들어 1시에 잠들기 시작해서 9시에 일어났는데 3시까지 뒤척였다면, 수면 시간은 6시간으로 기재된 게 아니라 8시간으로 기재됐습니다.

     tossNturn을 생각해보면 확실히 약점이 많은 데이터이긴 한 것 같아요. 정확하게 잠든 시간과 깨어난 시간을 알 수 없기 때문이죠. 추가로 데이터를 쌓아야한다면 정확하게 시간을 잴 수 있는 방법도 생각해볼 수도 있고, 컨디션 여부를 묻는 변수, 음주여부, 날씨 등의 변수를 추가하는 것도 생각해볼 수 있겠습니다. 그럼 좀더 다채롭고 재미있는 데이터가 되겠네요 ㅎㅎ

     충격적인 사실은 애플워치로 이런 수면 데이터 기록이 가능하다는 것이었습니다.. 저는 몰랐는데 이 얘기를 다른데서 했을 때 누가 그러더라구요. 그거 사과시계로 측정 가능할텐데 왜 힘들게 수기로 작성했냐고.. 혹시 본인 잠 시간을 알고 싶으신 분이 계시다면, 발전된 과학의 힘을 빌리시기를 추천드립니다!

     

Designed by Tistory.