regulares reemplazar palabras funcion extraer expresiones ejemplos comodines comando caracteres r sum matching fuzzy approximate

reemplazar - gsub r



Extrayendo información de la primera coincidencia aproximada de una cadena de texto en R(y sumando el número total de coincidencias) (3)

Voy a darte una solución base, pero realmente creo que este es un gran problema para la base y el paquete data.table es lo que se necesita (pero no sé cómo usar data.table muy bien:

dat <- data[order(data$date), ] Trim <- function (x) gsub("^//s+|//s+$", "", x) dat$text2 <- Trim(gsub("AT|THEN", "", dat$text)) dat2 <- split(dat, dat$text2) FUN <- function(x) { c(ID = x[1, 3], Sum = nrow(x), Original.Text = as.character(x[1, 1]), Original.Date = as.character(x[1, 2])) } data.frame(do.call(rbind, lapply(dat2, FUN)), row.names = NULL)

Realmente no sé qué tan cerca está cada cadena de texto, así que tal vez mi coincidencia exacta no sea apropiada, pero si ese es el caso, use agrep para desarrollar una nueva variable. Lo siento por la falta de anotaciones pero estoy presionada por el tiempo y creo que data.table es más apropiado de todos modos.

EDITAR: Sigo pensando que data.table es mejor y debería estar afuera, pero que correr en paralelo es inteligente. Estás en una máquina con Windows, así que esto funcionaría para usar varios núcleos de una computadora:

dat <- data[order(data$date), ] Trim <- function (x) gsub("^//s+|//s+$", "", x) dat$text2 <- Trim(gsub("AT|THEN", "", dat$text)) dat2 <- split(dat, dat$text2) FUN <- function(x) { c(ID = x[1, 3], Sum = nrow(x), Original.Text = as.character(x[1, 1]), Original.Date = as.character(x[1, 2])) } library(parallel) detectCores() #make sure you have > 1 core cl <- makeCluster(mc <- getOption("cl.cores", detectCores())) clusterExport(cl=cl, varlist=c("FUN", "dat2"), envir=environment()) x <- parLapply(cl, dat2, FUN) stopCluster(cl) #stop the cluster data.frame(do.call(rbind, x), row.names = NULL)

Tengo problemas para sumar coincidencias aproximadas de cadenas de texto, así como para extraer información de la cadena que se emparejó primero en el tiempo.

Tengo datos que se ven así:

text<-c("THEN it goes West","AT it falls East","it goes West", "it falls East", "AT it goes West") date<-c(2008,2009,2003,2006,2011) ID<-c(1,2,3,4,5) data<-cbind(text,date,ID) data<-as.data.frame(data)

Observe que las últimas cadenas de texto tienen mayúsculas "THEN" y "AT" agregadas a las cadenas de texto anteriores.

Me gustaría una tabla que se vea así:

ID Sum Originaltext Originaldate [1,] "4" "3" "it goes West" "2003" [2,] "2" "2" "it falls East" "2006"

Esto incluye:

El número de ID correspondiente al texto con la fecha más temprana (el texto "original" del que se derivaron los otros). Sumas de todas las coincidencias aproximadas para cada una. El texto correspondiente a la fecha más temprana. Y la fecha del texto correspondiente con la fecha más temprana.

Tengo decenas de millones de casos, por lo que tengo problemas para automatizar el proceso.

Ejecuto Windows 7 y tengo acceso a servidores de computación rápida.

IDEAS

#order them backwards in time data<-data[order(data$date, decreasing = TRUE),] #find the strings with the latest date pattern<-"AT|THEN" k <- vector("list", length(data$text)) for (j in 1:length(data$text)){ k[[j]]<- grep(pattern,data$text[[j]], ignore.case=FALSE) } k<-subset(data$text, k==1) k<-unique(k) #this is a problem, because case nos. 1 and 5 are still in the dataset, but they derive from the same tweet.

Desde aquí, puedo usar "agrep", pero no estoy seguro de en qué contexto. ¡Cualquier ayuda sería muy apreciada!

NOTA: Si bien las tres respuestas a continuación responden a mi pregunta de la forma en que originalmente la hice, no he mencionado que mis casos de texto varían incluso sin las palabras "AT" y "THEN". De hecho, la mayoría de ellos no coinciden exactamente. Debería haber puesto esto en la pregunta original. Sin embargo, todavía me encantaría una respuesta.

¡Gracias!


plyr puede ser demasiado lento dado el número de registros que mencionas, pero aquí hay una solución para ti:

library(stringr) data$original_text <- data$text data$text[grep("^THEN", data$text)] <- str_trim(str_sub(data$text[grep("^THEN", data$text)],6)) data$text[grep("^AT", data$text)] <- str_trim(str_sub(data$text[grep("^AT", data$text)],4)) result <- ddply(data, .(text), function(x) { sum <- nrow(x) x <- x[which(x$date==min(x$date)),] return(data.frame(id=unique(x$ID), Sum = sum, Originaltext = unique(x$original_text), Originaldate = unique(x$date))) }) > result[, -1] id Sum Originaltext Originaldate 1 4 2 it falls East 2006 2 3 3 it goes West 2003

Si tiene acceso a una máquina multinúcleo (4 o más núcleos), aquí hay una solución HPC

library(multicore) library(stringr) data$original_text <- data$text data$text[grep("^THEN", data$text)] <- str_trim(str_sub(data$text[grep("^THEN", data$text)],6)) data$text[grep("^AT", data$text)] <- str_trim(str_sub(data$text[grep("^AT", data$text)],4)) fux <- function(foo) { sum <- nrow(x) x <- x[which(x$date==min(x$date)),] return(data.frame(id=unique(x$ID), Sum = sum, Originaltext = unique(x$original_text), Originaldate = unique(x$date))) } x <- split(data, data$text) result <- mclapply(x, fux, mc.cores = 4, mc.preschedule = TRUE)


Una solución data.table que evita stringr . Estoy seguro de que esto podría mejorarse

Tratar con datos de texto

# make the factor columns character .data <- lapply(data, function(x) if(is.factor(x)) {as.character(x)} else { x}) library(data.table) DT <- as.data.table(.data) DT[, original_text := text] # using `%like% which is an easy data.table wrapper for grepl DT[text %like% "^THEN", text := substr(text, 6, nchar(text))] DT[text %like% "^AT", text := substr(text, 4, nchar(text))] # or avoiding the two vector scans and replacing in one fell swoop DT[,text := gsub(''(^THEN )|(^AT )'', '''', text)] DT[, c(sum=.N, .SD[which.min(date)]) ,by=text]

usando niveles de factor (podría ser más rápido)

# assuming that text is a factor DTF <- as.data.table(data) DTF[, original_text := text] levels_text <- DTF[, levels(text)] new_levels <- gsub(''(^THEN )|(^AT )'', x= levels_text ,'''') # reset the levels setattr(DTF[[''text'']], ''levels'', new_levels) # coerce to character and do the same count / min date DTF[, c(sum=.N, .SD[which.min(date)]) ,by=list(text = as.character(text))]