2017-01-28 14 views
5

tôi đã được đưa ra dữ liệu trong một file văn bản trông giống như:nhập dữ liệu có cấu trúc kém trong r

Measurement: mc 
Loop: 
var1=0, var2=-5, var3=1.8 
values: 
iteration  data 
0    1.203 
1    1.206 
2    2.206 
3    1.201 
4    1.204 
5    1.204 
6    1.204 
statistics: 
max   1.206 
min   1.201 
mean   1.204 
stddev  0.001 
avgdev  0.001 
failedtimes 0 

Measurement: mc 
Loop: 
var1=10, var2=-5, var3=1.8 
values: 
iteration  data 
0    1.203 
1    1.206 
2    2.206 
3    1.201 
statistics: 
max   1.206 
min   1.201 
mean   1.204 
stddev  0.001 
avgdev  0.001 
failedtimes 0 

tôi đang tìm cách để có được các dữ liệu trong một định dạng bình thường hơn như:

var1, var2, var3, iteration, data, 
    0, -5, 1.8,   0, 1.203, 
    0, -5, 1.8,   1, 1.206, 
    ... 
    10, -5, 1.8,   0, 1.203, 

Tôi đang gặp sự cố khi cố phân tích dữ liệu như thế này. xin giúp

+0

Các bạn đã thử sử dụng ' 'skip' read.table' và' đối số nrows' để nắm bắt 'iteration' và' dữ liệu' cột? – adatum

+0

Ồ, và nếu đó là tệp có định dạng rộng cố định, có 'read.fwf' cho điều đó. – adatum

Trả lời

6

Một cách là sử dụng một chút wee đơn giản regex và readLines để kéo ra các hàng có liên quan.

Dữ liệu của bạn

txt <- 
    "Measurement: mc 
Loop: 
var1=0, var2=-5, var3=1.8 
values: 
iteration  data 
0    1.203 
1    1.206 
2    2.206 
3    1.201 
4    1.204 
5    1.204 
6    1.204 
statistics: 
max   1.206 
min   1.201 
mean   1.204 
stddev  0.001 
avgdev  0.001 
failedtimes 0 

Measurement: mc 
Loop: 
var1=10, var2=-5, var3=1.8 
values: 
iteration  data 
0    1.203 
1    1.206 
2    2.206 
3    1.201 
statistics: 
max   1.206 
min   1.201 
mean   1.204 
stddev  0.001 
avgdev  0.001" 


# Read in : you can pass the file path instead of textConnection 
r = readLines(textConnection(txt)) 

# Find indices of relevant parts of string that you want to keep 
id1 = grep("var", r) 
id2 = grep("iteration", r) 
id3 = grep("statistics", r) 

# indices for iteration data 
m = mapply(seq, id2, id3-1) 

# Use read.table to parse the relevant rows 
lst <- lapply(seq_along(m), function(x) 
        cbind(read.table(text=r[id1][x], sep=","), #var data 
          read.table(text=r[m[[x]]], header=TRUE))) # iteration data 

dat <- do.call(rbind, lst) 

# Remove the var= text and convert to numeric 
dat[] <- lapply(dat, function(x) as.numeric(gsub("var\\d+=", "", x))) 
dat 
# V1 V2 V3 iteration data 
# 1 0 -5 1.8   0 1.203 
# 2 0 -5 1.8   1 1.206 
# 3 0 -5 1.8   2 2.206 
# 4 0 -5 1.8   3 1.201 
# 5 0 -5 1.8   4 1.204 
# 6 0 -5 1.8   5 1.204 
# 7 0 -5 1.8   6 1.204 
# 8 10 -5 1.8   0 1.203 
# 9 10 -5 1.8   1 1.206 
# 10 10 -5 1.8   2 2.206 
# 11 10 -5 1.8   3 1.201 

Có thể thực sự là một chút rõ ràng hơn để phân chia các dữ liệu trong các phần và sau đó áp dụng một hàm nghĩa

sp <- split(r, cumsum(grepl("measure", r, TRUE))) 

# Function to parse 
fun <- function(x){ 
    id1 = grep("var", x) 
    id2 = grep("iteration", x) 
    id3 = grep("statistics", x) 
    m = seq(id2, id3-1) 

    cbind(read.table(text=x[id1], sep=","), 
      read.table(text=x[m], header=TRUE)) 
} 

lst <- lapply(sp, fun) 

Sau đó, tiếp theo nue như trước

+0

Câu trả lời đầu tiên của bạn hoạt động tốt, ngoại trừ tôi phải sử dụng 'Map()' thay vì 'mapply()', không chắc chắn tại sao 'mapply()' không xuất ra một danh sách? – verigolfer

+0

@verigolfer; mapply đã làm việc trong ví dụ này (trong việc tạo thành danh sách các chỉ mục) vì các chỉ số cho mỗi lần lặp lại có độ dài khác nhau. Nếu dữ liệu của bạn có cùng định dạng, tôi nghĩ rằng điều này có thể đúng, nhưng yesr chắc chắn sẽ rõ ràng hơn khi sử dụng 'SIMPLIFY = FALSE' trong' mapply' hoặc 'Map' – user20650

3

Đây là đường dẫn đọc và xử lý nó. Giả sử dữ liệu nằm trong L theo Ghi chú ở cuối. Bạn có thể sẽ cần phải tạo điều này với một cái gì đó như L <- readLines("myfile.dat").

Cắt khoảng trắng đầu và cuối bằng cách sử dụng trimws - bước này có thể không cần thiết nhưng không thể làm tổn hại chỉ trong trường hợp dữ liệu không có khoảng trắng ở đầu dòng. Sau đó, grep ra dòng bắt đầu bằng một chữ số hoặc chứa var thay thế mỗi số v, a, r, = bằng dấu cách và thay thế bằng dấu phẩy bằng dòng mới. Điều đó đặt nó ở dạng read.table có thể đọc nó vào một khung dữ liệu 2 cột trong đó cột đầu tiên là 1, 2, 3 theo sau là số lặp và cột thứ hai là giá trị của var1, var2, var3data tất cả lặp lại cho mỗi nhóm. Chúng tôi tạo một biến nhóm bằng cách xác định các lần chạy tuần tự bằng cách sử dụng biểu thức cumsum(...) %/% 2. Điều này giả định rằng có ít nhất 2 lần lặp (0 và 1) cho mỗi nhóm. (Từ dữ liệu được hiển thị, nó sẽ cho biết rằng đây là trường hợp nhưng nếu không nó có thể được giải quyết bằng mã bổ sung như sau.) Cuối cùng, chia cho biểu thức nhóm và làm lại mỗi nhóm tách ra thành khung dữ liệu cần thiết.

library(purrr) 

L %>% 
    trimws %>% 
    grep(pattern = "^\\d|var", value = TRUE) %>% 
    chartr(old = "var=,", new = " \n") %>% 
    read.table(text = .) %>% 
    split(cumsum(c(FALSE, diff(.$V1) != 1)) %/% 2) %>% 
    map_df(function(x) data.frame(var1 = x[1, 2], var2 = x[2, 2], 
     var3 = x[3, 2],iteration = x[-(1:3), 1], data = x[-(1:3), 2])) 

cho:

var1 var2 var3 iteration data 
1  0 -5 1.8   0 1.203 
2  0 -5 1.8   1 1.206 
3  0 -5 1.8   2 2.206 
4  0 -5 1.8   3 1.201 
5  0 -5 1.8   4 1.204 
6  0 -5 1.8   5 1.204 
7  0 -5 1.8   6 1.204 
8 10 -5 1.8   0 1.203 
9 10 -5 1.8   1 1.206 
10 10 -5 1.8   2 2.206 
11 10 -5 1.8   3 1.201 

biến Này biến thể của mã cũng xử lý các trường hợp chỉ có một lần lặp, tức là lặp 0, và đơn giản hóa việc tính toán nhóm tại các chi phí của một vài nhiều dòng mã hơn. Ở đây hai trường hợp -9999 có thể là bất kỳ số nào không xuất hiện trong dữ liệu.

L %>% 
    grep(pattern = "^\\s*\\d|var", value = TRUE) %>% 
    sub(pattern = "var", replacement = "-9999 var") %>% 
    gsub(pattern = "[^0-9.,-]", replacement = " ") %>% 
    gsub(pattern = ",", replacement = "\n") %>% 
    strsplit("\\s+") %>% 
    unlist %>% 
    as.numeric %>% 
    split(cumsum(. == -9999)) %>% 
    map_df(function(x) { 
    x <- t(matrix(x[-1], 2)) 
    data.frame(var1 = x[1, 2], var2 = x[2, 2], var3 = x[3, 2], 
     iteration = x[-(1:3), 1], data = x[-(1:3), 2]) 
    }) 

dplyr/tidyr Chúng tôi luân phiên có thể sử dụng dplyr và tidyr gói.vars có 3 cột var1, var2var3 và một hàng cho mỗi nhóm. values có một cột chứa khung dữ liệu hai cột lồng nhau của dữ liệu lặp và dữ liệu và có một hàng cho mỗi nhóm nhưng mỗi hàng như vậy chứa một khung dữ liệu của nhiều hàng.

library(tidyr) 
library(dplyr) 

vars <- L %>% 
    grep(pattern = "var", value = TRUE) %>% 
    gsub(pattern = "[=,]", replacement = " ") %>% 
    read.table(text = ., col.names = c(NA, "var1", NA, "var2", NA, "var3")) %>% 
    select(var1, var2, var3) 

values <- L %>% 
    trimws %>% 
    grep(pattern = "^\\d", value = TRUE) %>% 
    read.table(text = ., col.names = c("iteration", "data")) %>% 
    mutate(g = cumsum(iteration == 0)) %>% 
    nest(-g) %>% 
    select(-g) 


cbind(vars, values) %>% unnest 

Lưu ý:

Lines <- "Measurement: mc 
Loop: 
var1=0, var2=-5, var3=1.8 
values: 
iteration  data 
0    1.203 
1    1.206 
2    2.206 
3    1.201 
4    1.204 
5    1.204 
6    1.204 
statistics: 
max   1.206 
min   1.201 
mean   1.204 
stddev  0.001 
avgdev  0.001 
failedtimes 0 

Measurement: mc 
Loop: 
var1=10, var2=-5, var3=1.8 
values: 
iteration  data 
0    1.203 
1    1.206 
2    2.206 
3    1.201 
statistics: 
max   1.206 
min   1.201 
mean   1.204 
stddev  0.001 
avgdev  0.001 
failedtimes 0" 
L <- readLines(textConnection(Lines)) 
+0

Rất hay. cảm ơn bạn. Tôi quan tâm đến toán tử '%>%' này. Có vẻ như bạn đang sử dụng như một đường ống. Có vẻ như một số phong cách mới trong R đã xuất hiện trong vài năm qua. – verigolfer

Các vấn đề liên quan