2011-11-27 25 views
18

Tôi đang cố gắng tìm ra cách tốt nhất để tạo một tệp JSON từ R. Tôi có khung dữ liệu sau đây tmp trong R.Các chiến lược để định dạng đầu ra JSON từ R

> tmp 
    gender age welcoming proud tidy unique 
1  1 30   4  4 4  4 
2  2 34   4  2 4  4 
3  1 34   5  3 4  5 
4  2 33   2  3 2  4 
5  2 28   4  3 4  4 
6  2 26   3  2 4  3 

Kết quả của dput(tmp) là như sau:

tmp <- structure(list(gender = c(1L, 2L, 1L, 2L, 2L, 2L), age = c(30, 
34, 34, 33, 28, 26), welcoming = c(4L, 4L, 5L, 2L, 4L, 3L), proud = c(4L, 
2L, 3L, 3L, 3L, 2L), tidy = c(4L, 4L, 4L, 2L, 4L, 4L), unique = c(4L, 
4L, 5L, 4L, 4L, 3L)), .Names = c("gender", "age", "welcoming", 
"proud", "tidy", "unique"), na.action = structure(c(15L, 39L, 
60L, 77L, 88L, 128L, 132L, 172L, 272L, 304L, 305L, 317L, 328L, 
409L, 447L, 512L, 527L, 605L, 618L, 657L, 665L, 670L, 708L, 709L, 
729L, 746L, 795L, 803L, 826L, 855L, 898L, 911L, 957L, 967L, 983L, 
984L, 988L, 1006L, 1161L, 1162L, 1224L, 1245L, 1256L, 1257L, 
1307L, 1374L, 1379L, 1386L, 1387L, 1394L, 1401L, 1408L, 1434L, 
1446L, 1509L, 1556L, 1650L, 1717L, 1760L, 1782L, 1814L, 1847L, 
1863L, 1909L, 1930L, 1971L, 2004L, 2022L, 2055L, 2060L, 2065L, 
2082L, 2109L, 2121L, 2145L, 2158L, 2159L, 2226L, 2227L, 2281L 
), .Names = c("15", "39", "60", "77", "88", "128", "132", "172", 
"272", "304", "305", "317", "328", "409", "447", "512", "527", 
"605", "618", "657", "665", "670", "708", "709", "729", "746", 
"795", "803", "826", "855", "898", "911", "957", "967", "983", 
"984", "988", "1006", "1161", "1162", "1224", "1245", "1256", 
"1257", "1307", "1374", "1379", "1386", "1387", "1394", "1401", 
"1408", "1434", "1446", "1509", "1556", "1650", "1717", "1760", 
"1782", "1814", "1847", "1863", "1909", "1930", "1971", "2004", 
"2022", "2055", "2060", "2065", "2082", "2109", "2121", "2145", 
"2158", "2159", "2226", "2227", "2281"), class = "omit"), row.names = c(NA, 
6L), class = "data.frame") 

Sử dụng gói rjson, tôi chạy dòng toJSON(tmp) trong đó sản xuất các tập tin JSON sau:

{"gender":[1,2,1,2,2,2], 
"age":[30,34,34,33,28,26], 
"welcoming":[4,4,5,2,4,3], 
"proud":[4,2,3,3,3,2], 
    "tidy":[4,4,4,2,4,4], 
    "unique":[4,4,5,4,4,3]} 

Tôi cũng đã thử nghiệm với gói RJSONIO; đầu ra của toJSON() giống nhau. Những gì tôi muốn sản xuất là cấu trúc sau:

{"traits":["gender","age","welcoming","proud", "tidy", "unique"], 
    "values":[ 
      {"gender":1,"age":30,"welcoming":4,"proud":4,"tidy":4, "unique":4}, 
      {"gender":2,"age":34,"welcoming":4,"proud":2,"tidy":4, "unique":4}, 
      .... 
      ] 

Tôi không chắc cách tốt nhất để làm điều này. Tôi nhận ra rằng tôi có thể phân tích nó theo từng dòng bằng cách sử dụng python nhưng tôi cảm thấy như có lẽ là một cách tốt hơn để làm điều này. Tôi cũng nhận ra rằng cấu trúc dữ liệu của tôi trong R không phản ánh meta-thông tin mong muốn trong tập tin JSON tôi (đặc biệt là dòng traits), nhưng tôi chủ yếu quan tâm đến việc sản xuất các dữ liệu định dạng giống như dòng

{"gender":1,"age":30,"welcoming":4,"proud":4,"tidy":4, "unique":4} 

như tôi có thể thêm dòng đầu tiên theo cách thủ công.


CHỈNH SỬA: Tôi đã tìm thấy một bài viết hữu ích tương tự và cung cấp giải pháp. Hàm này tạo ra một tệp JSON được định dạng từ một khung dữ liệu.

toJSONarray <- function(dtf){ 
clnms <- colnames(dtf) 

name.value <- function(i){ 
quote <- ''; 
# if(class(dtf[, i])!='numeric'){ 
if(class(dtf[, i])!='numeric' && class(dtf[, i])!= 'integer'){ # I modified this line so integers are also not enclosed in quotes 
quote <- '"'; 
} 

paste('"', i, '" : ', quote, dtf[,i], quote, sep='') 
} 

objs <- apply(sapply(clnms, name.value), 1, function(x){paste(x, collapse=', ')}) 
objs <- paste('{', objs, '}') 

# res <- paste('[', paste(objs, collapse=', '), ']') 
res <- paste('[', paste(objs, collapse=',\n'), ']') # added newline for formatting output 

return(res) 
} 
+0

năm đã đi vào từ câu hỏi này đã được hỏi. Tôi có thể đề nghị xem thư viện (jsonlite) không - ai đó đã cung cấp câu trả lời dưới đây. Nó không yêu cầu biến đổi() chuyển đổi và trực tiếp tạo ra kết quả đầu ra JSON dự kiến. – ripvlan

+1

@ripvlan - đánh dấu jsonlite là câu trả lời – djq

Trả lời

7

Sử dụng gói jsonlite:

> jsonlite::toJSON(list(traits = names(tmp), values = tmp), pretty = TRUE) 
{ 
    "traits": ["gender", "age", "welcoming", "proud", "tidy", "unique"], 
    "values": [ 
    { 
     "gender": 1, 
     "age": 30, 
     "welcoming": 4, 
     "proud": 4, 
     "tidy": 4, 
     "unique": 4 
    }, 
    { 
     "gender": 2, 
     "age": 34, 
     "welcoming": 4, 
     "proud": 2, 
     "tidy": 4, 
     "unique": 4 
    }, 
    { 
     "gender": 1, 
     "age": 34, 
     "welcoming": 5, 
     "proud": 3, 
     "tidy": 4, 
     "unique": 5 
    }, 
    { 
     "gender": 2, 
     "age": 33, 
     "welcoming": 2, 
     "proud": 3, 
     "tidy": 2, 
     "unique": 4 
    }, 
    { 
     "gender": 2, 
     "age": 28, 
     "welcoming": 4, 
     "proud": 3, 
     "tidy": 4, 
     "unique": 4 
    }, 
    { 
     "gender": 2, 
     "age": 26, 
     "welcoming": 3, 
     "proud": 2, 
     "tidy": 4, 
     "unique": 3 
    } 
    ] 
} 
+1

Xin chào Alex - Tôi thích câu trả lời này là tốt nhất. jsonlite hiểu data.frame và các kết quả đầu ra mà không có biến đổi alply()/apply() như được mô tả trong câu trả lời @civilstat ở trên. Ngoài ra - Tôi đã gặp vấn đề với RJSONIO mà tôi không thể giải quyết được vì tất cả các giá trị là mảng 1. jsonlite không có vấn đề này. – ripvlan

+0

cảm ơn vì phản hồi, tôi rất vui vì bạn thấy nó hữu ích. – Alex

4

Dường như với tôi bạn có thể làm điều này bằng cách gửi mỗi hàng của data.frame của bạn để JSON với tuyên bố thích hợp apply.

Đối với một hàng duy nhất:

library(RJSONIO) 

> x <- toJSON(tmp[1, ]) 
> cat(x) 
{ 
"gender": 1, 
"age":  30, 
"welcoming": 4, 
"proud": 4, 
"tidy": 4, 
"unique": 4 
} 

Toàn bộ data.frame:

x <- apply(tmp, 1, toJSON) 
cat(x) 
{ 
"gender": 1, 
"age":  30, 
"welcoming": 4, 
"proud": 4, 
"tidy": 4, 
"unique": 4 
} { 

... 

} { 
"gender": 2, 
"age":  26, 
"welcoming": 3, 
"proud": 2, 
"tidy": 4, 
"unique": 3 
} 
+0

Cảm ơn @Andrie, đó là một ý tưởng tuyệt vời. Tôi đang cố gắng tìm ra cách chèn một ',' vào cuối mỗi dòng bằng cách sử dụng một cái gì đó như thế này: 'x <- apply (tmp, 1, function (tmp) {paste (toJSON, ',')}) '. Có cách nào để thêm một cái gì đó vào những gì được trả về từ 'toJSON'? – djq

+0

Chỉ cần tìm ra: 'x <- áp dụng (tmp, 1, hàm (tmp) {dán (toJSON (tmp), ',')})'. Vẫn bị treo 'áp dụng'! – djq

+0

@celenius: Điều đó có vẻ nghi ngờ như bạn đang cố gắng viết các bit của JSON, điều này sẽ chỉ kết thúc trong nước mắt. Tốt hơn để thao tác các dữ liệu vào một hình thức mà gọi 'toJSON' cung cấp cho bạn những gì bạn muốn. Xem câu trả lời của tôi. –

14

xây dựng trên ý tưởng Andrie với apply, bạn có thể nhận được chính xác những gì bạn muốn bằng cách thay đổi biến tmp trước khi gọi toJSON.

library(RJSONIO) 
modified <- list(
    traits = colnames(tmp), 
    values = unname(apply(tmp, 1, function(x) as.data.frame(t(x)))) 
) 
cat(toJSON(modified)) 
+0

+1 Có, đồng ý đây là cách tiếp cận tốt hơn. – Andrie

+0

Một vấn đề tôi đã có với cả hai phương pháp ('rjson' và' RJSONIO') là chúng chuyển đổi tất cả các số thành chuỗi. Ví dụ '2' trở thành' "2" '. Đoạn mã tôi dán vào như một phần của câu hỏi của tôi tránh được vấn đề này vì nó kiểm tra 'số' và' số nguyên'. Có lẽ tôi nên thêm nó như là một câu trả lời. – djq

+0

@celenius: Giải pháp của tôi được áp dụng cho biến 'tmp' của bạn có số nguyên nguyên, không phải số nguyên được chuyển đổi thành chuỗi. Bạn có chắc bạn không làm điều gì đó ngớ ngẩn? –

9

xây dựng thêm về ý tưởng Andrie và Richie, sử dụng alply thay vì apply để tránh chuyển đổi số điện thoại để nhân vật:

library(RJSONIO) 
library(plyr) 
modified <- list(
    traits = colnames(tmp), 
    values = unname(alply(tmp, 1, identity)) 
) 
cat(toJSON(modified)) 

plyr của alply cũng tương tự như apply nhưng trả về một danh sách tự động; trong khi không có hàm phức tạp hơn trong câu trả lời của Richie Cotton, apply sẽ trả về một vectơ hoặc mảng. Và các bước bổ sung đó, bao gồm t, có nghĩa là nếu tập dữ liệu của bạn có bất kỳ cột nào không phải là số, các số sẽ được chuyển đổi thành chuỗi. Vì vậy, việc sử dụng alply tránh mối quan ngại đó.

Ví dụ, hãy tmp bộ dữ liệu của bạn và thêm

tmp$grade <- c("A","B","C","D","E","F") 

Sau đó, so sánh mã này (với alply) vs ví dụ khác (với apply).

2

Một tùy chọn khác là sử dụng split để chia data.frame của bạn với N hàng thành N data.frames bằng 1 hàng.

library(RJSONIO) 
modified <- list(
    traits = colnames(tmp), 
    values = split(tmp, seq_len(nrow(tmp))) 
) 
cat(toJSON(modified)) 
Các vấn đề liên quan