将 JavaScript 生成的数据导入 R 或 Stata
Import data generated by JavaScript into R or Stata
我得到了一个如下所示的 csv 文件:
id,v2,class
1,1,"{2=22.7, 0=4.8, 3=321}"
2,1,"{2=929.5, 1=11.2, 3=1229.8}"
3,2,"{2=50.9, 1=28.8}"
我需要制作此表格——更具体地说,将其导入 R
数据框或 Stata
。在一天结束时,我想要一个看起来像这样的 table:
id v2 class_0 class_1 class_2 class_3
1 1 4.8 0 22.7 321
2 1 0 11.2 929.5 1229.8
3 2 0 28.8 50.9 0
有问题的“列”(class) 包含关于在 table 中应成为 4 列的数据。但是请注意,值 0 不会显示在原始文件中。
背景
此文件是在使用 JavaScript 的 Google Earth Engine 中生成的。除了它确实是一个逗号分隔值文件这一事实之外,有问题的“列”(class)对我来说看起来像一个 JSON 对象(有道理,因为该文件是由 JavaScript) 生成的。但是,很明显这不是 JSON 文件。
鉴于在 R
中,我尝试将罪魁祸首列解释为 JSON,并执行了以下操作:
library("rjson")
df = read.csv(csv_file)
json_data = fromJSON(paste(df$waterClass, collapse=""))
> Error in fromJSON(paste(df$waterClass, collapse = "")) :
unexpected character "1"; expecting opening string quote (") for key value
运气不好。
我想我可以采用更暴力的方法,但我希望首先有一个更优雅的解决方案。
我们可以将每一行转换为DCF格式记录,然后使用read.dcf
读取它。首先将其读入DF0
,然后将每一行改造成DCF格式的记录,给出v
。然后使用 read.dcf
读取它,重新排列列并将它们转换为数字,给出数字矩阵。最后用 0 替换 NAs。没有使用包。
DF0 <- read.csv(text = Lines, as.is = TRUE)
v <- with(DF0, paste0("\nid:", id, "\nv2:", v2, chartr("{}=,", "\n :\n", class)))
v <- gsub(" ", "", v)
m <- read.dcf(textConnection(v))
nms <- c("id", "v2", sort(setdiff(colnames(m), c("id", "v2"))))
mm <- apply(m[, nms], 2, as.numeric)
mm[is.na(mm)] <- 0
mm
给出这个数字矩阵:
id v2 0 1 2 3
[1,] 1 1 4.8 0.0 22.7 321.0
[2,] 2 1 0.0 11.2 929.5 1229.8
[3,] 3 2 0.0 28.8 50.9 0.0
备注
可重现形式的输入:
Lines <- 'id,v2,class
1,1,"{2=22.7, 0=4.8, 3=321}"
2,1,"{2=929.5, 1=11.2, 3=1229.8}"
3,2,"{2=50.9, 1=28.8}"'
Tidyverse 方法:
library(tidyverse)
df <- read_csv('id,v2,class
1,1,"{2=22.7, 0=4.8, 3=321}"
2,1,"{2=929.5, 1=11.2, 3=1229.8}"
3,2,"{2=50.9, 1=28.8}"')
df_clean <- df %>%
separate_rows(class, sep = ',') %>% # separate dict elements
separate(class, c('key', 'value'), sep = '=') %>% # split key-value pairs
mutate(key = paste0('class_', parse_number(key)), # clean up
value = parse_number(value)) %>%
spread(key, value, fill = 0) # spread back to wide form
df_clean
#> # A tibble: 3 x 6
#> id v2 class_0 class_1 class_2 class_3
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 1 4.8 0 22.7 321
#> 2 2 1 0 11.2 930. 1230.
#> 3 3 2 0 28.8 50.9 0
您可以稍微修改一下以添加一些引号,然后 jsonlite 应该能够处理它:
library(jsonlite)
cbind(
dat[c("id","v2")],
stream_in(textConnection(
gsub("(\s+|\{)(.+?)=(.+?)(,|})", '\1"\2":\3\4', dat$class))
)
)
# Imported 3 records. Simplifying...
# id v2 2 0 3 1
#1 1 1 22.7 4.8 321 <NA>
#2 2 1 929.5 <NA> 1229.8 11.2
#3 3 2 50.9 <NA> <NA> 28.8
这是一个 Stata 解决方案,示例数据为 data.csv
:
import delimited using data.csv, clear
split class, parse(,)
drop class
reshape long class, i(id) j(which)
replace class = subinstr(class, "{", "", .)
replace class = subinstr(class, "}", "", .)
split class, parse("=") destring
drop class which
rename (class?) (which class_)
replace class_ = 0 if missing(class_)
drop if missing(which)
reshape wide class_, i(id) j(which)
mvencode class_*, mv(0)
list
+-------------------------------------------------+
| id class_0 class_1 class_2 class_3 v2 |
|-------------------------------------------------|
1. | 1 4.8 0 22.7 321 1 |
2. | 2 0 11.2 929.5 1229.8 1 |
3. | 3 0 28.8 50.9 0 2 |
+-------------------------------------------------+
我得到了一个如下所示的 csv 文件:
id,v2,class
1,1,"{2=22.7, 0=4.8, 3=321}"
2,1,"{2=929.5, 1=11.2, 3=1229.8}"
3,2,"{2=50.9, 1=28.8}"
我需要制作此表格——更具体地说,将其导入 R
数据框或 Stata
。在一天结束时,我想要一个看起来像这样的 table:
id v2 class_0 class_1 class_2 class_3
1 1 4.8 0 22.7 321
2 1 0 11.2 929.5 1229.8
3 2 0 28.8 50.9 0
有问题的“列”(class) 包含关于在 table 中应成为 4 列的数据。但是请注意,值 0 不会显示在原始文件中。
背景
此文件是在使用 JavaScript 的 Google Earth Engine 中生成的。除了它确实是一个逗号分隔值文件这一事实之外,有问题的“列”(class)对我来说看起来像一个 JSON 对象(有道理,因为该文件是由 JavaScript) 生成的。但是,很明显这不是 JSON 文件。
鉴于在 R
中,我尝试将罪魁祸首列解释为 JSON,并执行了以下操作:
library("rjson")
df = read.csv(csv_file)
json_data = fromJSON(paste(df$waterClass, collapse=""))
> Error in fromJSON(paste(df$waterClass, collapse = "")) :
unexpected character "1"; expecting opening string quote (") for key value
运气不好。
我想我可以采用更暴力的方法,但我希望首先有一个更优雅的解决方案。
我们可以将每一行转换为DCF格式记录,然后使用read.dcf
读取它。首先将其读入DF0
,然后将每一行改造成DCF格式的记录,给出v
。然后使用 read.dcf
读取它,重新排列列并将它们转换为数字,给出数字矩阵。最后用 0 替换 NAs。没有使用包。
DF0 <- read.csv(text = Lines, as.is = TRUE)
v <- with(DF0, paste0("\nid:", id, "\nv2:", v2, chartr("{}=,", "\n :\n", class)))
v <- gsub(" ", "", v)
m <- read.dcf(textConnection(v))
nms <- c("id", "v2", sort(setdiff(colnames(m), c("id", "v2"))))
mm <- apply(m[, nms], 2, as.numeric)
mm[is.na(mm)] <- 0
mm
给出这个数字矩阵:
id v2 0 1 2 3
[1,] 1 1 4.8 0.0 22.7 321.0
[2,] 2 1 0.0 11.2 929.5 1229.8
[3,] 3 2 0.0 28.8 50.9 0.0
备注
可重现形式的输入:
Lines <- 'id,v2,class
1,1,"{2=22.7, 0=4.8, 3=321}"
2,1,"{2=929.5, 1=11.2, 3=1229.8}"
3,2,"{2=50.9, 1=28.8}"'
Tidyverse 方法:
library(tidyverse)
df <- read_csv('id,v2,class
1,1,"{2=22.7, 0=4.8, 3=321}"
2,1,"{2=929.5, 1=11.2, 3=1229.8}"
3,2,"{2=50.9, 1=28.8}"')
df_clean <- df %>%
separate_rows(class, sep = ',') %>% # separate dict elements
separate(class, c('key', 'value'), sep = '=') %>% # split key-value pairs
mutate(key = paste0('class_', parse_number(key)), # clean up
value = parse_number(value)) %>%
spread(key, value, fill = 0) # spread back to wide form
df_clean
#> # A tibble: 3 x 6
#> id v2 class_0 class_1 class_2 class_3
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 1 4.8 0 22.7 321
#> 2 2 1 0 11.2 930. 1230.
#> 3 3 2 0 28.8 50.9 0
您可以稍微修改一下以添加一些引号,然后 jsonlite 应该能够处理它:
library(jsonlite)
cbind(
dat[c("id","v2")],
stream_in(textConnection(
gsub("(\s+|\{)(.+?)=(.+?)(,|})", '\1"\2":\3\4', dat$class))
)
)
# Imported 3 records. Simplifying...
# id v2 2 0 3 1
#1 1 1 22.7 4.8 321 <NA>
#2 2 1 929.5 <NA> 1229.8 11.2
#3 3 2 50.9 <NA> <NA> 28.8
这是一个 Stata 解决方案,示例数据为 data.csv
:
import delimited using data.csv, clear
split class, parse(,)
drop class
reshape long class, i(id) j(which)
replace class = subinstr(class, "{", "", .)
replace class = subinstr(class, "}", "", .)
split class, parse("=") destring
drop class which
rename (class?) (which class_)
replace class_ = 0 if missing(class_)
drop if missing(which)
reshape wide class_, i(id) j(which)
mvencode class_*, mv(0)
list
+-------------------------------------------------+
| id class_0 class_1 class_2 class_3 v2 |
|-------------------------------------------------|
1. | 1 4.8 0 22.7 321 1 |
2. | 2 0 11.2 929.5 1229.8 1 |
3. | 3 0 28.8 50.9 0 2 |
+-------------------------------------------------+