Преобразование логических данных из широкого в длинный формат в R

#r #reshape

#r #изменение формы

Вопрос:

У меня есть следующие данные:

 ID  cancer cancer_date stroke stroke_date diabetes diabetes_date
1    1       Feb2017     0     Jan2015      1         Jun2015
2    0       Feb2014     1     Jan2015      1         Jun2015
  

Я хотел бы получить

 ID condition date
1   cancer    xx
1   diabetes  xx
2   stroke    xx
2   diabetes  xx
  

Я попытался изменить форму и собрать, но это не делало того, что я хочу. Есть идеи, как я могу это сделать?

Ответ №1:

Это должно сделать это. Ключ к упрощению работы — изменить имена cancer stroke и diabetes в x_val , а затем вы можете использовать pivot_longer() from tidyr для выполнения работы.

 library(tidyr)
library(dplyr)
dat <- tibble::tribble(
~ID,  ~cancer, ~cancer_date, ~stroke, ~stroke_date, ~diabetes, ~diabetes_date,
1,    1,       "Feb2017",     0,     "Jan2015",      1,         "Jun2015",
2,    0,       "Feb2014",     1,     "Jan2015",      1,         "Jun2015")

dat %>% 
  rename("cancer_val" = "cancer",
         "stroke_val" = "stroke",
         "diabetes_val" = "diabetes") %>%
  pivot_longer(cols=-ID, 
               names_to = c("diagnosis", ".value"), 
               names_pattern="(.*)_(.*)") %>% 
  filter(val == 1)
# # A tibble: 4 x 4
#     ID diagnosis   val date   
#   <dbl> <chr>     <dbl> <chr>  
# 1     1 cancer        1 Feb2017
# 2     1 diabetes      1 Jun2015
# 3     2 stroke        1 Jan2015
# 4     2 diabetes      1 Jun2015

  

Ответ №2:

 library(data.table)
data <- data.table(ID = c(1, 2), cancer = c(1, 0), cancer_date = c("Feb2017", "Feb2014"), stroke = c(0, 1), stroke_date = c("Jan2015", "Jan2015"), diabetes = c(1, 1), diabetes_date = c("Jun2015", "Jun2015"))
datawide <-
  melt(data, id.vars = c("ID", "cancer", "stroke", "diabetes"), 
     measure.vars = c("cancer_date", "stroke_date", "diabetes_date"))
datawide[(cancer == 1 amp; variable == "cancer_date") |
           (stroke == 1 amp; variable == "stroke_date") |
           (diabetes == 1 amp; variable == "diabetes_date"), .(ID, condition = variable, date = value)]
  

Ответ №3:

Попробуйте это решение, используя pivot_longer() и переменную флага для фильтрации желаемых состояний. После поворота вы можете отфильтровать значения, отличные от нуля, и выбрать только одно значение. Здесь код:

 library(tidyverse)
#Code
df2 <- df %>% pivot_longer(cols = -c(ID,contains('_'))) %>%
  filter(value!=0) %>% rename(condition=name) %>% select(-value) %>%
  pivot_longer(-c(ID,condition)) %>%
  separate(name,c('v1','v2'),sep='_') %>%
  mutate(Flag=ifelse(condition==v1,1,0)) %>%
  filter(Flag==1) %>% select(-c(v1,v2,Flag)) %>%
  rename(date=value)
  

Вывод:

 # A tibble: 4 x 3
     ID condition date   
  <int> <chr>     <chr>  
1     1 cancer    Feb2017
2     1 diabetes  Jun2015
3     2 stroke    Jan2015
4     2 diabetes  Jun2015
  

Некоторые используемые данные:

 #Data
df <- structure(list(ID = 1:2, cancer = 1:0, cancer_date = c("Feb2017", 
"Feb2014"), stroke = 0:1, stroke_date = c("Jan2015", "Jan2015"
), diabetes = c(1L, 1L), diabetes_date = c("Jun2015", "Jun2015"
)), class = "data.frame", row.names = c(NA, -2L))
  

Если первое получение является сложным, вот еще один вариант:

 #Code 2
df2 <- df %>% mutate(across(everything(),~as.character(.))) %>%
  pivot_longer(cols = -c(ID)) %>%
  separate(name,c('condition','v2'),sep = '_') %>%
  replace(is.na(.),'val') %>%
  pivot_wider(names_from = v2,values_from=value) %>%
  filter(val==1) %>% select(-val)
  

Вывод:

 # A tibble: 4 x 3
  ID    condition date   
  <chr> <chr>     <chr>  
1 1     cancer    Feb2017
2 1     diabetes  Jun2015
3 2     stroke    Jan2015
4 2     diabetes  Jun2015