2013-05-07 16 views
6

Mam dataframe że zawiera kolumnę liczb takiego:Dzielenie długi ciąg na mniejsze ciągi

360010001001002 
360010001001004 
360010001001005 
360010001001006 

Chciałbym złamać na kawałki 2 cyfr, 3 cyfry, 5 cyfr, 1 cyfra 4 cyfry:

36 001 00010 0 1002 
36 001 00010 0 1004 
36 001 00010 0 1005 
36 001 00010 0 1006 

to wydaje się, że powinna być prosta, ale czytam dokumentację strsplit i nie mogę uporządkować jak zrobiłbym to przez długościach.

+0

jest głównym zamiarem a) ** konwertować wektor podłańcuchowych długości w pary indeksów ** lub b) ** dzielenie na df kolumny i rób to wydajnie **: rozbij fragmenty jako nowe oddzielne d.f. column (-> ddply (transform, ...)), lub po prostu wykonaj jakąś operację na łańcuchach (np. wstaw "-") w tej samej kolumnie? (-> ldply) – smci

+0

Mój problem jest już dawno rozwiązany, ale ponieważ zapytałeś ... tak: Chciałem te kawałki jako osobne kolumny. To numer identyfikacyjny. Musiałbym wrócić i wyglądać dokładnie, ale fragmenty mają znaczenie: "36" to stan, "001" powiat, "00010" blok lub coś takiego. – Amanda

+0

Dobrze, ale moje pytanie: czy to naprawdę nie miało dla ciebie znaczenia, czy podałeś arbitralny wektor 'widths = c (2,3,5,1,4)' zamiast zwykłych starych par indeksów: (1 , 2), (3,5), (6,10), (11,11), (12,15). Kilku respondentów zostało zawieszonych na temat tego, czy owa arytmetyczna informacja zbiorcza jest kluczową częścią twojego pytania. Okazuje się, że tak nie było. Możesz zmienić dla jasności. – smci

Odpowiedz

4

Przyjmując te dane:

x <- c("360010001001002", "360010001001004", "360010001001005", "360010001001006") 

try to:

read.fwf(textConnection(x), widths = c(2, 3, 5, 1, 4)) 

Jeśli numer jest x, należy zamienić x na as.character(x) w tym zestawieniu.

+0

+1 - całkiem schludny! Zapamiętam to. – Arun

+0

Po wykonaniu tego: 'foo $ county_id <- as.vector (gsub (foo $ fullfipsid, pattern =" .. (...). * ", Replace =" \\ 1 "))' dla każdego fragmentu . Pracował. Ale akceptuję tę odpowiedź b/c jest elegancka i działa. (Testowałem to) – Amanda

8

Można użyć substring (zakładając długość sznurka/liczba jest stała):

xx <- c(360010001001002, 360010001001004, 360010001001005, 360010001001006) 
out <- do.call(rbind, lapply(xx, function(x) as.numeric(substring(x, 
        c(1,3,6,11,12), c(2,5,10,11,15))))) 
out <- as.data.frame(out) 
+0

'ddply (mutate ...)' wydaje się bardziej elegancki niż 'do.call (rbind, ...)'? Zobacz moją odpowiedź poniżej. – smci

+0

i 'cumsum()' dla akumulacji indeksów – smci

4

wersja funkcjonalna:

split.fixed.len <- function(x, lengths) { 
    cum.len <- c(0, cumsum(lengths)) 
    start <- head(cum.len, -1) + 1 
    stop <- tail(cum.len, -1) 
    mapply(substring, list(x), start, stop) 
}  

a <- c(360010001001002, 
     360010001001004, 
     360010001001005, 
     360010001001006) 

split.fixed.len(a, c(2, 3, 5, 1, 4)) 
#  [,1] [,2] [,3] [,4] [,5] 
# [1,] "36" "001" "00010" "0" "1002" 
# [2,] "36" "001" "00010" "0" "1004" 
# [3,] "36" "001" "00010" "0" "1005" 
# [4,] "36" "001" "00010" "0" "1006" 
+0

+1 - fajne użytkowanie (jak zwykle) z mapply tutaj! :) – Arun

0

(Wow, to zadanie jest bardzo niezgrabne i bolesne w porównaniu do Pythona. Anyhoo ...)

PS Widzę teraz głównym zamiarem było konwertować wektorem fragmentu o długości do par indeksów. Można użyć cumsum(), a następnie posortować indeksy wszystko razem:

ll <- c(2,3,5,1,4) 
sort(c(1, cumsum(ll), (cumsum(ll)+1)[1:(length(ll)-1)])) 
# now extract these as pairs. 

Ale to dość bolesne. flodel - odpowiedź jest lepsza.

Co do faktycznego zadania podziału na d.f. kolumny, i robi to skutecznie:

stringr::str_sub() łączy elegancko z plyr::ddply()/ldply

require(plyr) 
require(stringr) 

df <- data.frame(value=c(360010001001002,360010001001004,360010001001005,360010001001006)) 
df$valc = as.character(df$value) 

df <- ddply(df, .(value), mutate, chk1=str_sub(valc,1,2), chk3=str_sub(valc,3,5), chk6=str_sub(valc,6,10), chk11=str_sub(valc,11,11), chk14=str_sub(valc,12,15)) 

#    value   valc chk1 chk3 chk6 chk11 chk14 
# 1 360010001001002 360010001001002 36 001 00010  0 1002 
# 2 360010001001004 360010001001004 36 001 00010  0 1004 
# 3 360010001001005 360010001001005 36 001 00010  0 1005 
# 4 360010001001006 360010001001006 36 001 00010  0 1006 
0

Można użyć tej funkcji z stringi pakietu

splitpoints <- cumsum(c(2, 3, 5, 1,4)) 
stri_sub("360010001001002",c(1,splitpoints[-length(splitpoints)]+1),splitpoints)