2013-05-07 10 views
6

Tôi có một dataframe trong đó bao gồm một cột các số như thế này:tách một chuỗi dài thành chuỗi nhỏ

360010001001002 
360010001001004 
360010001001005 
360010001001006 

Tôi muốn đột nhập vào khối của 2 chữ số, 3 chữ số, 5 chữ số, chữ số 1 , 4 chữ số:

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

Điều đó có vẻ đơn giản nhưng tôi đang đọc tài liệu về strsplit và tôi không thể phân loại cách tôi làm điều này theo độ dài.

+0

là mục đích chính của bạn a) ** chuyển đổi một vectơ chiều dài chuỗi con thành các cặp chỉ mục ** hoặc b) ** tách thành df cột, và làm điều đó một cách hiệu quả **: phá vỡ các phần ra như d.f. riêng biệt mới cột (-> ddply (transform, ...)) hoặc chỉ thực hiện một số thao tác chuỗi (ví dụ: chèn '-') trên cùng một cột? (-> ldply) – smci

+0

Vấn đề của tôi đã được giải quyết rất lâu, nhưng kể từ khi bạn hỏi ... vâng: Tôi muốn những đoạn đó là các cột riêng biệt. Họ là một số ID. Tôi sẽ phải quay trở lại và nhìn chính xác, nhưng các khối có ý nghĩa: '36' là tiểu bang,' 001' quận, '00010' khối điều tra dân số hoặc một cái gì đó. – Amanda

+0

Phải, nhưng câu hỏi của tôi a) là nó không thực sự quan trọng với bạn cho dù bạn chỉ định một vector tùy ý của 'widths = c (2,3,5,1,4)' thay vì cặp đồng bằng cũ của chỉ số: (1 , 2), (3,5), (6,10), (11,11), (12,15). Một số người trả lời đã bị treo lên về việc liệu tích lũy chỉ số-số học là một phần quan trọng của câu hỏi của bạn. Hóa ra là không. Bạn có thể viết lại cho rõ ràng. – smci

Trả lời

4

Giả sử dữ liệu này:

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

thử này:

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

Nếu x là số, sau đó thay thế x bằng as.character(x) trong tuyên bố này.

+0

+1 - khá gọn gàng! Tôi sẽ nhớ điều này. – Arun

+0

Tôi thực hiện việc này: 'foo $ county_id <- as.vector (gsub (foo $ fullfipsid, pattern =" .. (...). * ", Replace =" \\ 1 "))' cho mỗi đoạn . Đã làm việc. Nhưng tôi chấp nhận câu trả lời này b/c nó là thanh lịch và cũng hoạt động. (Tôi đã thử nghiệm nó) – Amanda

8

Bạn có thể sử dụng substring (giả sử chiều dài của chuỗi/số là cố định):

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 ...)' có vẻ thanh lịch hơn 'do.call (rbind, ...)'? Xem câu trả lời của tôi dưới đây. – smci

+0

và 'cumsum()' để tích lũy chỉ số – smci

4

Một phiên bản chức năng:

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 - sử dụng tốt (như thường lệ) của một cách dễ dàng ở đây! :) – Arun

0

(Wow, nhiệm vụ này là vô cùng phiền phức và đau đớn so với Python. Anyhoo ...)

PS tôi thấy bây giờ mục đích chính của bạn là để chuyển đổi một vector của chuỗi độ dài vào cặp chỉ số. Bạn có thể sử dụng cumsum(), sau đó sắp xếp các chỉ số tất cả cùng nhau:

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

Nhưng nó khá đau đớn. Câu trả lời của flodel cho điều đó là tốt hơn.

Khi thực hiện nhiệm vụ chia tách thành d.f. cột, và làm điều đó một cách hiệu quả:

stringr::str_sub() kết hợp thanh lịch với 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

Bạn có thể sử dụng chức năng này từ stringi gói

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