如何将JSON导入R并将其转换为表格?

10

我希望能够处理现在以JSON格式保存的数据。但是我对R非常陌生,对如何处理数据一无所知。您可以在下面看到我已经实现了什么。但首先,是我的代码:

library(rjson)
json_file <- "C:\\Users\\Saonkfas\\Desktop\\WOWPAPI\\wowpfinaljson.json"
json_data <- fromJSON(paste(readLines(json_file), collapse=""))

我成功获取了数据:

for (x in json_data){print (x)}

尽管输出看起来相当原始:

[[1]]
[[1]]$wins
[1] "118"

[[1]]$losses
[1] "40"
# And so on

请注意JSON数据有些嵌套。我可以使用Python创建表格,但似乎使用R更为复杂。

编辑:

我的JSON数据:

{
"play1": [
    {
        "wins": "118",
        "losses": "40",
        "max_killed": "7",
        "battles": "158",
        "plane_id": "4401",
        "max_ground_object_destroyed": "3"
    },
    {
        "wins": "100",
        "losses": "58",
        "max_killed": "7",
        "battles": "158",
        "plane_id": "2401",
        "max_ground_object_destroyed": "3"
    },
    {
        "wins": "120",
        "losses": "38",
        "max_killed": "7",
        "battles": "158",
        "plane_id": "2403",
        "max_ground_object_destroyed": "3"
    }
],

"play2": [
    {
        "wins": "12",
        "losses": "450",
        "max_killed": "7",
        "battles": "158",
        "plane_id": "4401",
        "max_ground_object_destroyed": "3"
    },
    {
        "wins": "150",
        "losses": "8",
        "max_killed": "7",
        "battles": "158",
        "plane_id": "2401",
        "max_ground_object_destroyed": "3"
    },
    {
        "wins": "120",
        "losses": "328",
        "max_killed": "7",
        "battles": "158",
        "plane_id": "2403",
        "max_ground_object_destroyed": "3"
    }
],

1
发布您的JSON数据部分。另外,尝试使用RJSONIO包。 - Fernando
1
你可以查看一下稍微更新的rjsonlite包,具体信息请参考这里:https://public.opencpu.org/posts/jsonlite-a-smarter-json-encoder/ - Stephen Henderson
3个回答

18

fromJSON返回一个列表,你可以使用*apply函数遍历每个元素。一旦知道该怎么做,将其转换为“表格”(数据帧是正确的R术语)就相当简单。

library(rjson)

# You can pass directly the filename
my.JSON <- fromJSON(file="test.json")

df <- lapply(my.JSON, function(play) # Loop through each "play"
  {
  # Convert each group to a data frame.
  # This assumes you have 6 elements each time
  data.frame(matrix(unlist(play), ncol=6, byrow=T))
  })

# Now you have a list of data frames, connect them together in
# one single dataframe
df <- do.call(rbind, df)

# Make column names nicer, remove row names
colnames(df) <- names(my.JSON[[1]][[1]])
rownames(df) <- NULL

df
  wins losses max_killed battles plane_id max_ground_object_destroyed
1  118     40          7     158     4401                           3
2  100     58          7     158     2401                           3
3  120     38          7     158     2403                           3
4   12    450          7     158     4401                           3
5  150      8          7     158     2401                           3
6  120    328          7     158     2403                           3

11

我认为jsonlite对于这项任务来说更加用户友好。 这里是三个JSON解析包的比较(偏向于jsonlite)。

library(jsonlite)
data <- fromJSON('path/to/file.json')

data
#> $play1
#   wins losses max_killed battles plane_id max_ground_object_destroyed
# 1  118     40          7     158     4401                           3
# 2  100     58          7     158     2401                           3
# 3  120     38          7     158     2403                           3
# 
# $play2
#   wins losses max_killed battles plane_id max_ground_object_destroyed
# 1   12    450          7     158     4401                           3
# 2  150      8          7     158     2401                           3
# 3  120    328          7     158     2403                           3
如果您想将这些列表名称合并到一个新列中,我建议使用dplyr::bind_rows而不是do.call(rbind, data)
library(dplyr)
data <- bind_rows(data, .id = 'play')

# Source: local data frame [6 x 7]

#    play  wins losses max_killed battles plane_id max_ground_object_destroyed
#   (chr) (chr)  (chr)      (chr)   (chr)    (chr)                       (chr)
# 1 play1   118     40          7     158     4401                           3
# 2 play1   100     58          7     158     2401                           3
# 3 play1   120     38          7     158     2403                           3
# 4 play2    12    450          7     158     4401                           3
# 5 play2   150      8          7     158     2401                           3
# 6 play2   120    328          7     158     2403                           3

注意,列的类型可能与您期望的不同(请注意,由于提供的 JSON 数据中所有数字都带引号,因此所有列都是字符)!

2017 年 11 月编辑:一种类型转换的方法是使用 mutate_if 来猜测字符列的预期类型。

data <- mutate_if(data, is.character, type.convert, as.is = TRUE)

1
你可以使用jsonlite中的rbind.pages代替加载reshape2,这可能可以与fromJSON一起调用。 - Rich Scriven
@RichardScriven 不错!我之前没注意到这个函数。虽然在这种情况下,它的效果类似于 do.call(rbind, data),但它不会将 play# 作为新变量保留(如果这对 OP 很重要的话)。 - Eric
@Eric,获取正确的列类型的最佳方法是什么?如果我将JSON文件转换为CSV并导入到R中,我会得到正确的类型,但是直接使用jsonlite导入会给我错误的类型。 - ant
@ant,很抱歉我无法回答你的问题,因为我不知道你的数据长什么样子,以及哪些类型是错误的。不过,最简单的方法可能就是将所有内容转换为数据框,然后根据需要强制转换列的类型。 - Eric

4

我更喜欢使用 tidyjson 而不是 rjson 和 jsonlite,因为它具有将多层嵌套的 JSON 对象转换为二维表格的简单工作流程。您可以轻松地使用这个来自 Github 的软件包解决您的问题。

devtools::install_github("sailthru/tidyjson")

library(tidyjson)
library(dplyr)

> json %>%  as.tbl_json %>% gather_keys %>% gather_array %>%  
+   spread_values(
+     wins = jstring("wins"),
+     losses = jstring("losses"),
+     max_killed = jstring("max_killed"),
+     battles = jstring("battles"),
+     plane_id = jstring("plane_id"),
+     max_ground_object_destroyed = jstring("max_ground_object_destroyed")
+    )

输出

  document.id   key array.index wins losses max_killed battles plane_id max_ground_object_destroyed
1           1 play1           1  118     40          7     158     4401                           3
2           1 play1           2  100     58          7     158     2401                           3
3           1 play1           3  120     38          7     158     2403                           3
4           1 play2           1   12    450          7     158     4401                           3
5           1 play2           2  150      8          7     158     2401                           3
6           1 play2           3  120    328          7     158     2403                           3

3
在您的代码中,变量 json 是如何定义的?在其他示例中,它是从磁盘加载的。 - Jochem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接