【问题标题】:Expanding a JSON column in R在 R 中扩展 JSON 列
【发布时间】:2015-07-23 22:42:56
【问题描述】:

我正在从 CSV 文件中读取数据表。 CSV 中的某些元素是 JSON 格式,因此其中一列具有 JSON 格式的数据,例如:

       user_id   tv_sec        action_info
  1:   47074     1426791420    {"foo": {"bar":12345,"baz":309}, "type": "type1"}
  2:   47074     1426791658    {"foo": '{"bar":23409,"baz":903}, "type": "type2"}
  3:   47074     1426791923    {"foo": {"bar":97241,"baz":218}, "type": "type3"} 

我想将action_info列展平,将数据添加为列,如下:

       user_id   tv_sec        bar     baz    type
  1:   47074     1426791420    12345   309    type1
  2:   47074     1426791658    23409   903    type2
  3:   47074     1426791923    97241   218    type3

我不确定如何实现这一点。我找到了一个库,可以在 R (RJSONIO) 中将字符串转换为 JSON,但我很难弄清楚下一步该做什么。当我尝试使用命令userActions[,.(fromJSON(action_info))] 尝试将action_info 列中的所有行转换为JSON 时,我基本上得到了一个数据表,其中似乎以某种方式累积的所有值对我来说并不完全清楚。例如,使用我得到的(非示例)数据运行它:

                                                    V1
1: 2.188603e+12,2.187628e+12,2.186202e+12,1.164000e+03
2:                                               type1
Warning messages:
1: In if (is.na(encoding)) return(0L) :
  the condition has length > 1 and only the first element will be used
2: In if (is.na(i)) { :
  the condition has length > 1 and only the first element will be used

所以,我想弄清楚:

  1. 如何对列进行操作以将其从 JSON 转换为值(虽然我认为我这样做是正确的,但我不确定)
  2. 如何在当前或新数据表中获取值并从中创建列。

【问题讨论】:

  • 您会看到错误,因为 action_infofactor 而不是字符串。您可以在读取数据时使用stringsAsFactors=FALSE,也可以在之后将其转换为字符as.character(df$action_info),然后使用fromJSON。问题是它根本不是一个有效的 JSON。是您的确切数据吗?
  • 这不是我的确切数据。我已将 JSON 修复为有效;对于这个问题,我深表歉意。
  • 我的数据中也遇到了同样的问题,并在那里修复了它。现在我不再收到该错误。编辑问题。

标签: json r csv


【解决方案1】:

相当丑陋但应该可以:

library(dplyr)
library(data.table)

lapply(as.character(df$action_info), RJSONIO::fromJSON) %>% 
    lapply(function(e) list(bar=e$foo[1], baz=e$foo[2], type=e$type)) %>% 
    rbindlist() %>%
    cbind(df) %>% 
    select(-action_info)

【讨论】:

    【解决方案2】:

    数据:

    library(data.table)
    df <- data.table(structure(list(user_id = c(47074L, 47074L, 47074L), tv_sec = c(1426791420L, 
    1426791658L, 1426791923L), action_info = c("{\"foo\": {\"bar\":12345,\"baz\":309}, \"type\": \"type1\"}", 
    "{\"foo\": {\"bar\":23409,\"baz\":903}, \"type\": \"type2\"}", 
    "{\"foo\": {\"bar\":97241,\"baz\":218}, \"type\": \"type3\"}"
    )), .Names = c("user_id", "tv_sec", "action_info"), row.names = c(NA, 
    -3L), class = "data.frame"))
    

    这是使用data_table 的一种方法:

    df[, c('bar', 'baz', 'type'):=as.list(unlist(fromJSON(action_info[1]))),
       by=action_info]
    

    它是如何工作的:

    by=action_info 本质上确保我们只为每个唯一的action_info 调用一次fromJSON(在您的情况下每行一次);这是因为fromJSON 不适用于矢量化输入。

    fromJSON(action_info[1])action_info 转换为 JSON([1] 很有可能您有多行具有相同的action_info,因为fromJSON 不适用于矢量输入)。

    unlist 使嵌套的“foo: {bar...}”变平(执行fromJSON(df$action_info[1])unlist(fromJSON(df$action_info[1])) 以了解我的意思)。

    as.list 将结果转换回一个列表,每个“列”有一个元素(data.table 需要这个来执行多重赋值)

    然后c('bar', 'baz', 'type'):= 将输出分配回列。

    请注意,我们不按名称匹配,因此“bar”始终是 JSON 的第一部分,“baz”始终是第二部分,依此类推。如果您的 action_info 可以有 {bar: ..., baz: ...} 以及{baz: ..., bar: ...} 第二个的baz 将分配给bar 列。如果您想更聪明并按名称分配,则必须想出更聪明的方法(因为您可以使用as.list(...)[c('foo.bar', 'foo.baz', 'type')] 来确保在分配之前元素的顺序正确)。

    【讨论】:

      猜你喜欢
      • 2021-02-12
      • 2020-09-21
      • 1970-01-01
      • 1970-01-01
      • 2020-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多