2016-02-18 9 views
5

Ho una funzione che funziona, per un data.table (data.frame) di 1 riga, ma non lavoro per l'intero data.table. Vorrei estendere la funzione per prendere in considerazione tutte le righe dei dati di input.table.estensione di una funzione che accetta un data.table come argomento per utilizzare la tabella completa (invece di un sottoinsieme)

Il nocciolo dell'argomento è il seguente:

A data.table (tryshort3) se un campo è una stringa, deve essere sostituita con un'altra stringa da un'altra data.table (mapping), MRE come segue :

#this is the original data.table 
tryshort3 <- structure(list(country = c("AT", "AT", "MT", "DE", "CH", "XK" 
), name = c("ASDF AG", "ASDF GMBH", "ASDF DF", "ASDF KG", "ASDF SA", 
"ASDF DAF"), address = c("ACDSTR. 3", "ACDSTR. 4", "ACDSTR. 5", 
"ACDSTR. 6", "ACDSTR. 7", "ACDSTR. 8")), .Names = c("country", 
"name", "address"), row.names = c(NA, -6L), class = c("data.table", 
"data.frame")) 



#this is the "mapping 
mapping <- structure(list(country = c("AT", "AT", "DE", "DE", "HU"), short.form = c("AG", 
"GMBH", "GMBH", "EV", "EV"), long.form = c("AKTIENGESELLSCHAFT", 
"GESELLSCHAFT MIT BESCHRANKTER HAFTUNG", "GESELLSCHAFT MIT BESCHRANKTER HAFTUNG", 
"EINGETRAGENE VEREIN", "EGYENI VALLALKOZO")), .Names = c("country", 
"short.form", "long.form"), row.names = c(NA, -5L), class = c("data.table", 
"data.frame"), sorted = "country") 


#this is the function that I am using (please not that both data.tables are keyed, but that has currently no say in the output (just avoids throwing an error): 

substituting_short_form <- function(input) { 
    #supply one data.frame of 1 row, the other data.frame is external to the function 
    #get country from input 
    setkey(input,country) 
    setkey(mapping,country) 
    matched_country <- input$country 
    #subset of mapping to only the country from the input 
    matched_map <- mapping[country == matched_country] 
    #get list of short.forms from matched 
    list_of_relevant_short_forms <- matched_map[,short.form] 
    #which one matches will return true if there is any match, THIS IS A NUMBER THAT WILL HAVE TO BE MATCHED TO mapping again to retrieve the correct form 
    #error catching for when there is no short form found, or no country found if there is no long form it does not matter! 
    indextrue <- tryCatch(which(unlist(lapply(list_of_relevant_short_forms, function(y) grepl(y, input$name)))), error = function(e) return(input)) 
    #substitute 
    pattern_to_substitute <- paste0("(\\s|^)", matched_map[indextrue,short.form], "(\\s|$)") 
    pattern_to_replace <- paste0("\\1", matched_map[indextrue,long.form], "\\2") 
    input$name[1] <- gsub(pattern = pattern_to_substitute, replacement = pattern_to_replace,input$name , perl = TRUE) 
    return(input) 
} 

in breve, cosa questa funzione sta facendo, sta prendendo tryshort3 asn un ingresso (attualmente solo lavorando con tryshort3[1,]) e sostituisce nel campo "nome" il valore trovato nella tabella mapping, in questo modo:

> tryshort3[1,] 
    country name address 
1:  AT ASDF AG ACDSTR. 3 
> substituting_short_form(tryshort3[1,]) 
    country     name address 
1:  AT ASDF AKTIENGESELLSCHAFT ACDSTR. 3 

Quello che vorrei, fornisco come input la piena data.table, e ottenere lo stesso risultato (un data.table di stessa lunghezza), ecco il mio risultato atteso:

country     name address 
1:  AT ASDF AKTIENGESELLSCHAFT ACDSTR. 3 
2:  AT ASDF GESELLSCHAFT MIT BESCHRANKTER HAFTUNG ACDSTR. 4 
3:  CH ASDF SA ACDSTR. 7 
4:  DE ASDF KG ACDSTR. 6 
5:  MT ASDF DF ACDSTR. 5 
6:  XK ASDF DAF ACDSTR. 8 

La soluzione che vorrei sarebbe qualcosa all'interno della funzione apply(tryshort3, 1, function(x) substituting_short_form(x)), forse utilizzando le funzionalità di indicizzazione di entrambi i dati.tables, o forse usando gapply da nlme da dentro?

risposta

4

forse si può provare in diverse fasi:

# create the shortform variable in tryshort3 
tryshort3[, short.form := sub(".+\\s([^s]+)$", "\\1", name)] 

# add the info from mapping 
tryshort3long <- merge(tryshort3, mapping, all.x=TRUE, by=c("country", "short.form")) 

# replace the short form by long form in the name and suppress the variables you don't need 
# (thanks to @DavidArenburg for the simplification of the "replace" part!) 
tryshort3long[!is.na(long.form), 
       name := paste(sub(" .*", "", name), long.form) 
       ][, c("long.form", "short.form") := NULL] 

tryshort3long 
    # country          name address 
# 1:  AT     ASDF AKTIENGESELLSCHAFT ACDSTR. 3 
# 2:  AT ASDF GESELLSCHAFT MIT BESCHRANKTER HAFTUNG ACDSTR. 4 
# 3:  CH         ASDF SA ACDSTR. 7 
# 4:  DE         ASDF KG ACDSTR. 6 
# 5:  MT         ASDF DF ACDSTR. 5 
# 6:  XK         ASDF DAF ACDSTR. 8 

NB: mi dispiace Ho appena messo per il tuo esempio data.table e non come una funzione

+0

grazie a @David! :-) Ho sentito che c'era un modo per evitare il ifelse ;-) – Cath

3

Il problema con apply è che costringerà il suo argomento a una matrice. Provare con un semplice ciclo:

lst <- list() 
for(i in 1:nrow(tryshort3)) lst[[i]] <- substituting_short_form(tryshort3[i,]) 
rbindlist(lst) 
# country          name address 
# 1:  AT     ASDF AKTIENGESELLSCHAFT ACDSTR. 3 
# 2:  AT ASDF GESELLSCHAFT MIT BESCHRANKTER HAFTUNG ACDSTR. 4 
# 3:  MT         ASDF DF ACDSTR. 5 
# 4:  DE         ASDF KG ACDSTR. 6 
# 5:  CH         ASDF SA ACDSTR. 7 
# 6:  XK         ASDF DAF ACDSTR. 8 
+0

Non ho letto nulla qui, ma forse controlla 'set' se stai già eseguendo un ciclo' for' ... –

Problemi correlati