【问题标题】:Define row and column separators for a data frame为数据框定义行和列分隔符
【发布时间】:2019-06-20 20:08:07
【问题描述】:

我导入了一个数据集,不幸的是,它没有定义任何分隔符,也没有在列或行中定义。我试图寻找一个选项来定义特定的行分隔符,但找不到适用于这种情况的选项。

df1 <- data.frame("V1" = "{lat:45.493,lng:-76.4886,alt:22400,call:COFPQ,icao:C056P,registration:X-VLMP,sqk:6232,trak:328,spd:null,postime:2019-01-15 16:10:39},
                  {lat:45.5049,lng:-76.5285,alt:23425,call:COFPQ,icao:C056P,registration:X-VLMP,sqk:6232,trak:321,spd:null,postime:2019-01-15 16:11:50},
                  {lat:45.5049,lng:-76.5285,alt:24000,call:COFPQ,icao:C056P,registration:X-VLMP,sqk:6232,trak:321,spd:null,postime:2019-01-15 16:11:50},
                  {lat:45.5049,lng:-76.5285,alt:24000,call:COFPQ,icao:C056P,registration:X-VLMP,sqk:6232,trak:321,spd:null,postime:2019-01-15 16:11:50}")
df2  <- data.frame("V1" = "{lat:45.493,lng:-76.4886,alt:22400,call:COFPQ,icao:C056P,registration:X-VLMP,sqk:6232,trak:328,spd:null,postime:2019-01-15 16:10:39},
                  {lat:45.5049,lng:-76.5285,alt:23425,call:COFPQ,icao:C056P,registration:X-VLMP,sqk:6232,trak:321,spd:null,postime:2019-01-15 16:11:50},
                  {lat:45.5049,lng:-76.5285,alt:24000,call:COFPQ,icao:C056P,registration:X-VLMP,sqk:6232,trak:321,spd:null,postime:2019-01-15 16:11:50},
                  {lat:45.5049,lng:-76.5285,alt:24000,call:COFPQ,icao:C056P,registration:X-VLMP,sqk:6232,trak:321,spd:null,postime:2019-01-15 16:11:50}")
newdf <- rbind(df1,df2)

这是我目前正在努力处理的数据模型。理想情况下,这种情况下的行分隔符必须定义为“},{”,列分隔符定义为“,”。我尝试将此模式设置为选项卡并定义不同的分隔符,但这要么返回错误(尝试使用 TidyR 中的单独行),要么什么也不做。

希望大家帮忙

【问题讨论】:

  • 怎么样subset(read.csv(text = paste(gsub("[{}]", "\n", newdf$V1), collapse="\n"), header = FALSE, stringsAsFactors = FALSE, strip.white = TRUE), V1 != "")`
  • 这行得通,列没有命名,1/2 行是空的,但没有数据丢失。谢谢!

标签: r


【解决方案1】:

这看起来像不完整(不正确)的 JSON,因此我建议您将其升级到规范,然后使用已知工具对其进行解析。一些问题,很容易缓解:

  1. sqk 应该有一个逗号分隔符,可能是复制/粘贴问题。根据您的流程,这可能被概括为任何“数字字母”级数。 (编辑:您的更新似乎已经解决了这个问题,所以我会删除它。如果您仍然需要它,我建议您使用非常直白的gsub("([^,])sqk:", "\\1,sql:", s)。)
  2. 标签(例如,lataltsql)都应该用双引号引起来。
  3. 需要引用非数字数据,特别是日期。
  4. 3 的例外情况:null 应保持不加引号。
  5. “列表”中有多个“字典”,即从{...},{...}[{...},{...}]

附注您的数据:我用stringsAsFactors=FALSE 读了它们,因为我们不需要因子。

fixjson <- function(s) {
  gsub(",+", ",",
       paste(
         gsub('"sqk":([^,]+)', '"sqk":"\\1"',
              gsub("\\s*\\b([A-Za-z]+)\\s*(?=:)", '"\\1"', # note 2
                   gsub('(?<=:)"(-?[0-9.]+|null)"', "\\1", # notes 3, 4
                        gsub("(?<=:)([^,]+)\\b", "\"\\1\"", # quote all data
                             s, perl = TRUE), perl = TRUE), perl = TRUE)),
         collapse = "," )
       )
}
fixjson(df1$V1)
# [1] "{\"lat\":45.493,\"lng\":-76.4886,\"alt\":22400,\"call\":\"COFPQ\",\"icao\":\"C056P\",\"registration\":\"X-VLMP\",\"sqk\":\"6232\",\"trak\":328,\"spd\":null,\"postime\":\"2019-01-15 16:10:39\"},\n                  {\"lat\":45.5049,\"lng\":-76.5285,\"alt\":23425,\"call\":\"COFPQ\",\"icao\":\"C056P\",\"registration\":\"X-VLMP\",\"sqk\":\"6232\",\"trak\":321,\"spd\":null,\"postime\":\"2019-01-15 16:11:50\"},\n                  {\"lat\":45.5049,\"lng\":-76.5285,\"alt\":24000,\"call\":\"COFPQ\",\"icao\":\"C056P\",\"registration\":\"X-VLMP\",\"sqk\":\"6232\",\"trak\":321,\"spd\":null,\"postime\":\"2019-01-15 16:11:50\"},\n                  {\"lat\":45.5049,\"lng\":-76.5285,\"alt\":24000,\"call\":\"COFPQ\",\"icao\":\"C056P\",\"registration\":\"X-VLMP\",\"sqk\":\"6232\",\"trak\":321,\"spd\":null,\"postime\":\"2019-01-15 16:11:50\"}"

从这里开始,我们使用定义明确的 json 解析器(来自 jsonliteRJSONIO,两者都使用相似的 API):

jsonlite::fromJSON(paste("[", fixjson(df1$V1), "]", sep=""))
#       lat      lng   alt  call  icao registration  sqk trak spd             postime
# 1 45.4930 -76.4886 22400 COFPQ C056P       X-VLMP 6232  328  NA 2019-01-15 16:10:39
# 2 45.5049 -76.5285 23425 COFPQ C056P       X-VLMP 6232  321  NA 2019-01-15 16:11:50
# 3 45.5049 -76.5285 24000 COFPQ C056P       X-VLMP 6232  321  NA 2019-01-15 16:11:50
# 4 45.5049 -76.5285 24000 COFPQ C056P       X-VLMP 6232  321  NA 2019-01-15 16:11:50

从这里,rbind 根据需要。 (请注意,null 文字被翻译成 R 的 NA,在我看来这是“应该的”。)

后续建议:您可以直接在您的postime 列上使用as.POSIXct;我希望您确定您的所有数据都在同一个时区,因为该字段不包含任何提示。

最后,您提到了一些非 ASCII 字符会影响作品的内容。我最近的编辑包括为使用 iconv(例如,使用 \\s*)引入的空间增加了一些稳健性,因此以下内容可能对您来说就足够了:

jsonlite::fromJSON( paste("[", fixjson(iconv(df2$V1, "latin1", "ASCII", sub="")), "]") )

https://stackoverflow.com/a/9935242/3358272建议使用iconv

【讨论】:

  • 是的,它是一个导入的带有谷歌地图信息的 HTML 源,以及节点的位置。我会尽快尝试您的解决方案,并告诉您进展如何。
  • 虽然很小,但我用dQuote 替换了硬编码的双引号,以防(不太可能?)某些数据包含嵌入的双引号。有几种方法可能会出错,因此 (1) 如果您确定不会包含其他字段,则不需要最后一次编辑; (2)如果数据曾经被引用,这将双引号它们,不好,可以防范; (3)如果发生其他事情,谁知道这会如何破裂。
  • 刚试了一下,原来的数据还包括一些数字和字符类的混合,比如“icao:C065E0”或者call:CGMPB。你建议只删除这些吗?或者,我可以将它们添加到数据集中?
  • 错误:词法错误:json 文本中的字符无效。 [{“lat”:45.493,“lng”:-76。 (就在这里)------^ 过程已完成,尽管在尝试应用 json 行时出现错误。
  • @Thejohn,每次聊天都会更新答案。抱歉花了这么长时间(计算以及我回到这里并更新答案)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-01
  • 1970-01-01
  • 2021-05-11
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
相关资源
最近更新 更多