1

我有一个包含此类键值对的字符串 s,我想从中构造数据框,

s="{'#JJ': 121, '#NN': 938, '#DT': 184, '#VB': 338, '#RB': 52}"
r1<-sapply(strsplit(s, "[^0-9_]+",as.numeric),as.numeric)
r2<-sapply(strsplit(s, "[^A-Z]+",as.numeric),as.character)
d<-data.frame(id=r2,value=r1)

是什么赋予了:

r1
     [,1]
[1,]   NA
[2,]  121
[3,]  938
[4,]  184
[5,]  338
[6,]   52
 r2
     [,1]
[1,] ""  
[2,] "JJ"
[3,] "NN"
[4,] "DT"
[5,] "VB"
[6,] "RB"

 d
  id value
1       NA
2 JJ   121
3 NN   938
4 DT   184
5 VB   338
6 RB    52

首先,我希望在使用正则表达式后没有 NA 和 ""。我认为它应该类似于 {2,} 表示从第二次出现匹配所有内容,但我不能在 R 中做到这一点。

我想做的另一个想法是:拥有一个带有如下列的数据框:

                                                              m
1   {'#JJ': 121, '#NN': 938, '#DT': 184, '#VB': 338, '#RB': 52}
2       {'#NN': 168, '#DT': 59, '#VB': 71, '#RB': 5, '#JJ': 35}
3      {'#JJ': 18, '#NN': 100, '#DT': 23, '#VB': 52, '#RB': 11}
4      {'#NN': 156, '#JJ': 39, '#DT': 46, '#VB': 67, '#RB': 21}
5       {'#NN': 112, '#DT': 39, '#VB': 57, '#RB': 8, '#JJ': 32}
6  {'#DT': 236, '#NN': 897, '#VB': 420, '#RB': 122, '#JJ': 240}
7     {'#NN': 316, '#RB': 25, '#DT': 66, '#VB': 112, '#JJ': 81}
8      {'#NN': 198, '#DT': 29, '#VB': 85, '#RB': 37, '#JJ': 44}
9                                                   {'#RB': 30}
10     {'#NN': 373, '#DT': 48, '#VB': 71, '#RB': 21, '#JJ': 36}
11       {'#NN': 49, '#DT': 17, '#VB': 23, '#RB': 11, '#JJ': 8}
12  {'#NN': 807, '#JJ': 135, '#DT': 177, '#VB': 315, '#RB': 69}

我想遍历每一行并将其数值拆分为由键命名的列。

显示几行的示例,我希望它看起来像:

在此处输入图像描述

4

2 回答 2

4

我会使用解析 JSON 的东西,你的数据似乎是:

s <- "{'#JJ': 121, '#NN': 938, '#DT': 184, '#VB': 338, '#RB': 52}"

parse.one <- function(s) {
  require(rjson)
  v <- fromJSON(gsub("'", '"', s))
  data.frame(id = gsub("#", "", names(v)),
             value = unlist(v, use.names = FALSE))  
}

parse.one(s)
#   id value
# 1 JJ   121
# 2 NN   938
# 3 DT   184
# 4 VB   338
# 5 RB    52

对于问题的第二部分,我将通过函数的稍微修改的版本parse.onelapply然后让 plyr 的rbind.fill函数将各个部分对齐在一起,同时用 填充缺失值NA

df <- data.frame(m = c(
  "{'#JJ': 121, '#NN': 938, '#DT': 184, '#VB': 338, '#RB': 52}",
  "{'#NN': 168, '#DT': 59, '#VB': 71, '#RB': 5, '#JJ': 35}",
  "{'#JJ': 18, '#NN': 100, '#DT': 23, '#VB': 52, '#RB': 11}",
  "{'#JJ': 12, '#VB': 5}"
))

parse.one <- function(s) {
  require(rjson)
  y <- fromJSON(gsub("'", '"', s))
  names(y) <- gsub("#", "", names(y))
  as.data.frame(y)
}

library(plyr)
rbind.fill(lapply(df$m, parse.one))
#    JJ  NN  DT  VB RB
# 1 121 938 184 338 52
# 2  35 168  59  71  5
# 3  18 100  23  52 11
# 4  12  NA  NA   5 NA
于 2013-08-28T09:54:23.377 回答
2

现在,我将为您问题的第一部分提供解决方案。清理你的字符串并使用read.table

s="{'#JJ': 121, '#NN': 938, '#DT': 184, '#VB': 338, '#RB': 52}"
read.table(text = gsub(",", "\n", gsub("[{|}|#]", "", s)), 
           header = FALSE, sep = ":", strip.white=TRUE)
#   V1  V2
# 1 JJ 121
# 2 NN 938
# 3 DT 184
# 4 VB 338
# 5 RB  52

concat.split对于第二部分,这是使用我编写的名为“splitstackshape”的包的另一种选择:

样本数据:

df <- data.frame(m = c(
  "{'#JJ': 121, '#NN': 938, '#DT': 184, '#VB': 338, '#RB': 52}",
  "{'#NN': 168, '#DT': 59, '#VB': 71, '#RB': 5, '#JJ': 35}",
  "{'#JJ': 18, '#NN': 100, '#DT': 23, '#VB': 52, '#RB': 11}"
))

与上面类似的清理,加上一个“id”列。

df$m <- gsub("[{|}|#]", "", df$m)
df$id <- 1:nrow(df)

加载“splitstackshape”包:

# install.packages("splitstackshape")
library(splitstackshape)
df2 <- concat.split(concat.split.multiple(df, "m", ",", "long"), 
                    "m", ":", drop = TRUE)
## df2 <- df2[complete.cases(df2), ] ## 
## ^^ might be necessary if there are NAs in the resulting data.frame

数据现在采用易于操作的“长”格式:

df2
#    id time m_1 m_2
# 1   1    1  JJ 121
# 2   2    1  NN 168
# 3   3    1  JJ  18
# 4   1    2  NN 938
# 5   2    2  DT  59
# 6   3    2  NN 100
# 7   1    3  DT 184
# 8   2    3  VB  71
# 9   3    3  DT  23
# 10  1    4  VB 338
# 11  2    4  RB   5
# 12  3    4  VB  52
# 13  1    5  RB  52
# 14  2    5  JJ  35
# 15  3    5  RB  11

下面是一个使用dcast“reshape2”包处理数据的例子:

library(reshape2)
dcast(df2, id ~ m_1, value.var="m_2")
#   id  DT  JJ  NN RB  VB
# 1  1 184 121 938 52 338
# 2  2  59  35 168  5  71
# 3  3  23  18 100 11  52
于 2013-08-28T09:40:44.403 回答