Начало и конец периода во фрейме данных

#r #dataframe

Вопрос:

Я хотел бы вернуть значение начала и конца фрейма данных на основе содержащихся в нем данных. Если есть только нули, чем я хотел бы заполнить начальный и конечный столбцы NA.

Структура данных:

введите описание изображения здесь

Выход:

введите описание изображения здесь

Примеры данных:

 structure(list(ID = c(1, 2, 3), A1 = c(1, 1,0), A2 = c(1, 1,0), A3 = c(0, 
1,0), A4 = c(0, 1,0), A5 = c(0, 1,0)), class = c("spec_tbl_df", "tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -3L), spec = structure(list(
    cols = list(ID = structure(list(), class = c("collector_double", 
    "collector")), A1 = structure(list(), class = c("collector_double", 
    "collector")), A2 = structure(list(), class = c("collector_double", 
    "collector")), A3 = structure(list(), class = c("collector_double", 
    "collector")), A4 = structure(list(), class = c("collector_double", 
    "collector")), A5 = structure(list(), class = c("collector_double", 
    "collector"))), default = structure(list(), class = c("collector_guess", 
    "collector")), skip = 1L), class = "col_spec"))
 

Пример кода (не работает со строками O):

 start <- names(df1)[-1][max.col(df1[-1], "first")]
end <- names(df1)[-1][max.col(df1[-1], "last")]
data.frame(ID = df1$ID, start, end)
 

Ответ №1:

Работает ли это:

 library(dplyr)
library(tidyr)
library(stringr)
df %>% pivot_longer(-ID) %>% group_by(ID) %>% 
  mutate(s = cumsum(value)) %>% mutate(s = na_if(s,0)) %>% 
    transmute(start = str_c('A',min(s)), end = str_c('A',max(s))) %>% distinct()
# A tibble: 3 x 3
# Groups:   ID [3]
     ID start end  
  <dbl> <chr> <chr>
1     1 A1    A2   
2     2 A1    A5   
3     3 NA    NA   
 

Ответ №2:

Используя базовые функции и цикл for, вы можете просмотреть все строки и отметить самый низкий и самый высокий столбец, содержащий 1. Однако он не заметил бы никаких перерывов в этой полосе. Если ваша полоса 1 прерывается a 0 , это не будет отображаться в результате.

 id = c()
start = c()
end = c()
for(i in 1:dim(df)[1]){
  id = c(id,df$ID[i])
  row = df[i,-1]
  start = c(start,names(row)[min((1:length(row))[row==1])])
  end = c(end,names(row)[max((1:length(row))[row==1])])
}

out = data.frame(ID=id,
                 start=start,
                 end=end)

 

На выходе получается:

 > out
  ID start  end
1  1    A1   A2
2  2    A1   A5
3  3  <NA> <NA>
 

Ответ №3:

 
library(tidyverse)
df1 %>% group_by(ID) %>% #rowwise() %>%
  summarise(start = list(names(cur_data())[as.logical(cur_data())]),
         end = unlist(map(start, ~last(.x))),
         start = unlist(map(start, ~first(.x))),
         .groups = 'drop')

#> # A tibble: 3 x 3
#>      ID start end  
#>   <dbl> <chr> <chr>
#> 1     1 A1    A2   
#> 2     2 A1    A5   
#> 3     3 <NA>  <NA>
 

Создан в 2021-06-16 гг. с помощью пакета reprex (версия 2.0)

Ответ №4:

Ниже приведена небольшая программа, которая может помочь. Однако это будет работать только в том случае, если вы уверены, что в ряду единиц нет нулей. Ваши примерные данные и пример кода предполагают это.

 #your data
df1 <- structure(list(ID = c(1, 2, 3), A1 = c(1, 1,0), A2 = c(1, 1,0), A3 = c(0, 1,0), A4 = c(0, 1,0), A5 = c(0, 1,0)), class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame"), row.names = c(NA, -3L), spec = structure(list(cols = list(ID = structure(list(), class = c("collector_double", "collector")), A1 = structure(list(), class = c("collector_double",  "collector")), A2 = structure(list(), class = c("collector_double", "collector")), A3 = structure(list(), class = c("collector_double", "collector")), A4 = structure(list(), class = c("collector_double", "collector")), A5 = structure(list(), class = c("collector_double", "collector"))), default = structure(list(), class = c("collector_guess", "collector")), skip = 1L), class = "col_spec"))

#use the library data.table
library(data.table)
df1 <- data.table(din)

#make a sum of by ID (by row)
df1[,sumUSE:=sum(.SD), by=ID]

#last
df1[,end:=names(df1)[(df1[,sumUSE] 1)]]
df1[end=="ID", end:=NA]

#first
df1[,start:=names(df1)[2]]
df1[is.na(end), start:=NA]

print(df1)
#   ID A1 A2 A3 A4 A5 sumUSE  end start
#1:  1  1  1  0  0  0      2   A2    A1
#2:  2  1  1  1  1  1      5   A5    A1
#3:  3  0  0  0  0  0      0 <NA>  <NA>