2011-11-28 13 views
20

Mi piacerebbe dividere un vettore di stringhe di caratteri (nomi di persone) in due colonne (vettori). Il problema è che alcune persone hanno un cognome "a due parole". Mi piacerebbe dividere il nome e il cognome in due colonne. Posso tagliare e prendere i primi nomi usando il codice qui sotto ma il cognome mi sfugge. (guardate obs 29 nel seguente esempio per avere un'idea come la Ford ha un "cognome" di Pantera L che deve essere tenuto insieme)Divisione di una stringa sul primo spazio

Quello che ho tentato di fare finora;

x<-rownames(mtcars) 
unlist(strsplit(x, " .*")) 

Quello che mi piacerebbe che a guardare come:

  MANUF  MAKE 
27   Porsche  914-2 
28   Lotus  Europa 
29   Ford  Pantera L 
30   Ferrari  Dino 
31   Maserati Bora 
32   Volvo  142E 

risposta

25

L'espressione regolare rexp corrisponde alla parola all'inizio della stringa, a uno spazio facoltativo, quindi al resto della stringa. Le parentesi sono sottoespressioni a cui si accede come backreferences \\1 e \\2.

rexp <- "^(\\w+)\\s?(.*)$" 
y <- data.frame(MANUF=sub(rexp,"\\1",x), MAKE=sub(rexp,"\\2",x)) 
tail(y) 
#  MANUF  MAKE 
# 27 Porsche  914-2 
# 28 Lotus Europa 
# 29  Ford Pantera L 
# 30 Ferrari  Dino 
# 31 Maserati  Bora 
# 32 Volvo  142E 
+0

@ Joshua Ullrich Bello. Grazie per la spiegazione. –

0

Se si può fare modello e la corrispondenza del gruppo, mi piacerebbe provare qualcosa di simile (non testata):

\s+(.*)\s+(.*) 
+4

Solo così sai, regex in R funzionano in modo leggermente diverso. Per lo meno, è necessario aggiungere un altro \ di fronte a ogni s, solo per evitare un errore. – joran

0

Penso che la ricerca di [^\s]+ funzionerebbe. Non testato.

17

Per me, la funzione di Hadley colsplit nel pacchetto reshape2 è la più intuitiva per questo scopo. Il modo in cui Joshua è più generale (cioè può essere usato ovunque sia possibile usare un'espressione regolare) e flessibile (se si desidera modificare le specifiche); ma la funzione colsplit si adatta perfettamente a questa impostazione specifica:

library(reshape2) 
y <- colsplit(x," ",c("MANUF","MAKE")) 
tail(y) 
#  MANUF  MAKE 
#27 Porsche  914-2 
#28 Lotus Europa 
#29  Ford Pantera L 
#30 Ferrari  Dino 
#31 Maserati  Bora 
#32 Volvo  142E 
+0

Molto bello l'uso della divisione colonne. Grazie. –

+0

+1 Davvero interessante, dato che avevo assunto 'colsplit' restituirà più di tre colonne in questo caso. Quanto ero sbagliato. – Andrie

7

Ancora un altro modo di farlo:

str_split da stringr gestirà la scissione, ma la restituisce in una forma diversa (una lista, come strsplit fa). Tuttavia, manipolare nella forma corretta è semplice.

library(stringr) 
split_x <- str_split(x, " ", 2) 
(y <- data.frame(
    MANUF = sapply(split_x, head, n = 1), 
    MAKE = sapply(split_x, tail, n = 1) 
)) 

Oppure, come Hadley accennato nei commenti, con str_split_fixed.

y <- as.data.frame(str_split_fixed(x, " ", 2)) 
colnames(y) <- c("MANUF", "MAKE") 
y 
+0

@Riche un'altra soluzione tramite un pacchetto Hadley Wickham. Grazie per aver condiviso –

+2

Sarebbe ancora meglio usare 'str_split_fixed' – hadley

+1

È interessante notare che questa risposta + il commento di hadley è correlato alla soluzione' colsplit' perché 'colsplit' usa' str_split_fixed'. –

11

Qui ci sono due approcci:

1) strsplit. Questo approccio utilizza solo funzioni nel nucleo di R e nessuna espressione regolare complessa. Sostituire il primo spazio con una virgola (utilizzando sub e nongsub), strsplit sulla virgola e poi rbind in una matrice 2 colonna:

mat <- do.call("rbind", strsplit(sub(" ", ";", x), ";")) 
colnames(mat) <- c("MANUF", "MAKE") 

2) strapply in pacchetto gsubfn Ecco uno -liner usando strapply nel pacchetto gsubfn. Le due parti parentesi dell'espressione regolare acquisiscono rispettivamente la prima e la seconda colonna desiderate e la funzione (che è specificata nella notazione formula - è la stessa che specifica function(x, y) c(MANUF = x, MAKE = y)) le afferra e aggiunge nomi.L'argomento simplify=rbind viene utilizzato per trasformarlo in una matrice come nella soluzione precedente.

library(gsubfn) 
mat <- strapply(x, "(\\S+)\\s+(.*)", ~ c(MANUF = x, MAKE = y), simplify = rbind) 

Nota: In entrambi i casi una matrice "character", mat, viene restituito. Se un frame di dati di "character" colonne si desidera aggiungere questo:

DF <- as.data.frame(mat, stringsAsFactors = FALSE) 

omettere l'argomento stringsAsFactors se "factor" colonne sono ricercati.

+0

Ho appena controllato di nuovo qui. In realtà mi è piaciuto il fatto che la tua soluzione numero 1 fosse la migliore tra quelle fornite. Grazie e scusa per il ritorno successivo. –

Problemi correlati