从R中的.txt文件解析JSON数组 - 几个大文件

时间:2018-02-07 11:00:14

标签: json r parsing twitter tweets

我最近从Twitter上下载了大量的推文。我的起点是大约400个包含推文ID的.txt文件。在运行工具之后,使用Tweet ID从Twitter上删除推文,并且对于每个.txt文件,我都有大量的推文ID,我得到一个包含JSON字符串的非常大的.txt文件。每个JSON字符串都包含有关Tweet的所有信息。下面是我的单驱动器的超链接,其中包含我正在处理的文件(一旦我开始工作,我将代码应用于其他文件):

https://1drv.ms/t/s!At39YLF-U90fhKAp9tIGJlMlU0qcNQ

我一直在尝试解析每个文件中的每个JSON字符串但没有成功。我的目标是将每个文件转换为R中的大型数据帧。每一行都是Tweet,每列都是Tweet中的一个功能。鉴于它们的性质,“文本”和“#39;列将非常大(它将包含推文的正文),而“#”位置'会很短。每个JSON字符串的格式都相同,每个文件最多可以有一百万个字符串。

我尝试了几种方法(如下所示)来获得我需要的但没有成功的方法:

library('RJSONIO')library('RCurl')
json_file <- fromJSON("Pashawar_test.txt")
json_file2 = RJSONIO::fromJSON(json_file)

错误(函数(classes,fdef,mtable):   无法为签名'&#34;列表&#34;,&#34;缺少&#34;'

找到函数'fromJSON'的继承方法

我的另一次尝试:

library('RJSONIO')
json_file <- fromJSON("Pashawar_test.txt")
text <- json_file[['text']]
idstr <- json_file[['id_str']]

此代码似乎只解析文件中的第一个JSON字符串。我之所以这么说,是因为当我试图选择&#39; text&#39;或者&#39; id_str&#39;,我只得到一个实例。还值得指出的是&#39; json_file&#39;是一个大型列表,大小为52.7mb,而源文件为335mb。

2 个答案:

答案 0 :(得分:1)

尝试stream_in包的jsonlite功能。您的文件包含每行的JSON。您可以逐行阅读并通过fromJSON进行转换,也可以直接使用stream_in,这是为了处理这种文件/连接。

require(jsonlite)
filepath<-"path/to/your/file"
#method A: read each line and convert
content<-readLines(filepath)
#this will take a while
res<-lapply(content,fromJSON)

#method B: use stream_in
con<-file(filepath,open="rt")
#this will take a while
res<-stream_in(con)

请注意,stream_in也会简化结果,将其强制转换为data.frame,这可能会更加方便。

答案 1 :(得分:1)

这是[n] ewline [d] elimited [json](ndjson)文件,它是为ndjson包量身定制的。所述包比jsonlite::stream_in() 非常快得多并产生“完全平坦”的数据帧。后一部分(“完全平坦”)不是始终人们真正需要的东西,因为它可以构成一个非常宽的结构(在你的情况下,1,012列,因为它扩展了所有嵌套组件)但你得到你需要什么,而不必自己去除任何东西。

str()甚至glimpse()的输出太大而无法在此处显示,但这就是您使用它的方式。

注意我重命名了你的文件,因为.json.gz通常是如何存储ndjson(我的包可以处理gzip的json文件):

library(ndjson)
library(tidyverse)

twdf <- tbl_df(ndjson::stream_in("~/Desktop/pashwar-test.json.gz"))
## dim(twdf)
## [1] 75008  1012

说完了......

我或者建议使用Apache Drill,因为你有很多这些文件并且它们相对较大。 Drill会让你(最终)将这些转换成镶木地板并显着加快速度,并且有一个与Drill(sergeant)接口的包:

library(sergeant)
library(tidyverse)

db <- src_drill("dbserver")
twdf <- tbl(db, "dfs.json.`pashwar-test.json.gz`")

glimpse(twdf)
## Observations: 25
## Variables: 28
## $ extended_entities         <chr> "{\"media\":[]}", "{\"media\":[]}", "{\"m...
## $ quoted_status             <chr> "{\"entities\":{\"hashtags\":[],\"symbols...
## $ in_reply_to_status_id_str <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N...
## $ in_reply_to_status_id     <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N...
## $ created_at                <chr> "Tue Dec 16 10:13:47 +0000 2014", "Tue De...
## $ in_reply_to_user_id_str   <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N...
## $ source                    <chr> "<a href=\"http://twitter.com/download/an...
## $ retweeted_status          <chr> "{\"created_at\":\"Tue Dec 16 09:28:17 +0...
## $ quoted_status_id          <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N...
## $ retweet_count             <int> 220, 109, 9, 103, 0, 398, 0, 11, 472, 88,...
## $ retweeted                 <chr> "false", "false", "false", "false", "fals...
## $ geo                       <chr> "{\"coordinates\":[]}", "{\"coordinates\"...
## $ is_quote_status           <chr> "false", "false", "false", "false", "fals...
## $ in_reply_to_screen_name   <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N...
## $ id_str                    <dbl> 5.447975e+17, 5.447975e+17, 5.447975e+17,...
## $ in_reply_to_user_id       <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N...
## $ favorite_count            <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
## $ id                        <dbl> 5.447975e+17, 5.447975e+17, 5.447975e+17,...
## $ text                      <chr> "RT @afneil: Heart-breaking beyond words:...
## $ place                     <chr> "{\"bounding_box\":{\"coordinates\":[]},\...
## $ lang                      <chr> "en", "en", "en", "en", "en", "en", "en",...
## $ favorited                 <chr> "false", "false", "false", "false", "fals...
## $ possibly_sensitive        <chr> NA, "false", NA, "false", NA, "false", NA...
## $ coordinates               <chr> "{\"coordinates\":[]}", "{\"coordinates\"...
## $ truncated                 <chr> "false", "false", "false", "false", "fals...
## $ entities                  <chr> "{\"user_mentions\":[{\"screen_name\":\"a...
## $ quoted_status_id_str      <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N...
## $ user                      <chr> "{\"id\":25968369,\"id_str\":\"25968369\"...

BUT

你已经设法创建了真正不一致的JSON。并非所有具有嵌套内容的字段都以这种方式一致地表示,而Drill的新手会发现制作防弹SQL有些挑战,这将帮助他们在所有场景中消除这些数据。

如果您只需要“已经平坦”位的数据,请尝试钻取。

如果您需要嵌套数据,并且不想与jsonlite::stream_in()中的取消进行斗争或者在使用Drill forcedsting时遇到困难,那么,我建议使用ndjson,如第一个示例中所述,然后将你真正需要的部分划分为更易于管理,更整洁的数据框架。