定义数据框的行和列分隔符

时间:2019-01-27 18:33:49

标签: r

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

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中的sepet_rows),要么什么都不做。

希望你们能帮忙

1 个答案:

答案 0 :(得分:3)

这看起来像不完整(不正确)的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,在我看来,这是“应有的”。)

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

最后,您提到了有关非ASCII字符使作品更加混乱的内容。我最近的编辑为使用iconv(例如,使用\\s*)引入的空格增加了一些鲁棒性,因此以下内容可能就足够了:

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

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