vectores tablas listas leer filtrar espaƱol ejemplos datos data crear r dataframe group-by run-length-encoding

listas - tablas en r



AgrupaciĆ³n de dataframe R por valores conectados (4)

Aquí hay otro intento de usar rle y aggregate desde la base R:

rl <- rle(df$State) newdf <- data.frame(ID=df$ID, State=rep(1:length(rl$lengths),rl$lengths)) newdf <- aggregate(ID~State, newdf, FUN = function(x) c(minID=min(x), maxID=max(x))) newdf$State <- rl$values # State ID.minID ID.maxID # 1 A 1 2 # 2 B 3 5 # 3 A 6 8 # 4 C 9 10

datos

df <- structure(list(ID = 1:10, State = c("A", "A", "B", "B", "B", "A", "A", "A", "C", "C")), .Names = c("ID", "State"), class = "data.frame", row.names = c(NA, -10L))

No encontré una solución para este problema de agrupación común en R:

Este es mi conjunto de datos original

ID State 1 A 2 A 3 B 4 B 5 B 6 A 7 A 8 A 9 C 10 C

Este debería ser mi conjunto de datos resultante agrupado

State min(ID) max(ID) A 1 2 B 3 5 A 6 8 C 9 10

Entonces, la idea es ordenar el conjunto de datos primero por la columna ID (o una columna de marca de tiempo). Luego, todos los estados conectados sin espacios vacíos se deben agrupar y se deben devolver los valores mínimo y máximo de ID. Está relacionado con el método rle, pero esto no permite el cálculo de valores máximos y mínimos para los grupos.

¿Algunas ideas?


Aquí hay un método que usa la función rle en la base R para el conjunto de datos que proporcionó.

# get the run length encoding temp <- rle(df$State) # construct the data.frame newDF <- data.frame(State=temp$values, min.ID=c(1, head(cumsum(temp$lengths) + 1, -1)), max.ID=cumsum(temp$lengths))

que devuelve

newDF State min.ID max.ID 1 A 1 2 2 B 3 5 3 A 6 8 4 C 9 10

Tenga en cuenta que rle requiere un vector de caracteres en lugar de un factor, por lo que utilizo el argumento as.is a continuación.

Como @ cryo111 notas en los comentarios a continuación, el conjunto de datos podría ser marcas de tiempo desordenadas que no corresponden a las longitudes calculadas en rle . Para que este método funcione, primero deberá convertir las marcas de tiempo en un formato de fecha y hora, con una función como as.POSIXct , use df <- df[order(df$ID),] y luego emplee una ligera alteración del método anterior:

# get the run length encoding temp <- rle(df$State) # construct the data.frame newDF <- data.frame(State=temp$values, min.ID=df$ID[c(1, head(cumsum(temp$lengths) + 1, -1))], max.ID=df$ID[cumsum(temp$lengths)])

datos

df <- read.table(header=TRUE, as.is=TRUE, text="ID State 1 A 2 A 3 B 4 B 5 B 6 A 7 A 8 A 9 C 10 C")


Tu podrías intentar:

library(dplyr) df %>% mutate(rleid = cumsum(State != lag(State, default = ""))) %>% group_by(rleid) %>% summarise(State = first(State), min = min(ID), max = max(ID)) %>% select(-rleid)

O como se menciona por @alistaire en los comentarios, puede mutar dentro de group_by() con la misma sintaxis, combinando los dos primeros pasos. Robar data.table::rleid() y usar summarise_all() para simplificar:

df %>% group_by(State, rleid = data.table::rleid(State)) %>% summarise_all(funs(min, max)) %>% select(-rleid)

Lo que da:

## A tibble: 4 × 3 # State min max # <fctr> <int> <int> #1 A 1 2 #2 B 3 5 #3 A 6 8 #4 C 9 10


Una idea con data.table :

require(data.table) dt <- fread("ID State 1 A 2 A 3 B 4 B 5 B 6 A 7 A 8 A 9 C 10 C") dt[,rle := rleid(State)] dt2<-dt[,list(min=min(ID),max=max(ID)),by=c("rle","State")]

lo que da:

rle State min max 1: 1 A 1 2 2: 2 B 3 5 3: 3 A 6 8 4: 4 C 9 10

La idea es identificar secuencias con rleid y luego obtener el min y el max de ID por la tupla y el State .

puedes eliminar la columna rle con

dt2[,rle:=NULL]

Encadenado:

dt2<-dt[,list(min=min(ID),max=max(ID)),by=c("rle","State")][,rle:=NULL]

Puede acortar el código anterior aún más utilizando rleid interior de rleid :

dt2 <- dt[, .(min=min(ID),max=max(ID)), by=.(State, rleid(State))][, rleid:=NULL]