【问题标题】:Parsing JSON arrays from a .txt file in R - several large files从 R 中的 .txt 文件解析 JSON 数组 - 几个大文件
【发布时间】:2018-07-17 15:29:28
【问题描述】:

我最近从 Twitter 下载了大量推文。我的出发点是大约 400 个包含 Tweet ID 的 .txt 文件。运行工具后,使用推文 ID 从 Twitter 抓取推文,对于我拥有的每个包含大量推文 ID 列表的 .txt 文件,我会得到一个包含 JSON 字符串的非常大的 .txt 文件。每个 JSON 字符串都包含有关推文的所有信息。下面是我的一个驱动器的超链接,其中包含我正在处理的文件(一旦我得到这个工作,我会将代码应用到其他文件):

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

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

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

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

(函数(类,fdef,mtable)中的错误: 无法为签名“list”、“missing”找到函数“fromJSON”的继承方法

我的另一个尝试:

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

此代码似乎只解析文件中的第一个 JSON 字符串。我这样说是因为当我尝试选择“text”或“id_str”时,我只会得到一个实例。还值得指出的是,“json_file”是一个大列表,大小为 52.7mb,而源文件为 335mb。

【问题讨论】:

    标签: json r parsing twitter tweets


    【解决方案1】:

    尝试jsonlite 包的stream_in 功能。您的文件包含每一行的 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,这可能更方便。

    【讨论】:

    • nicola - 谢谢你的建议。我运行了您建议的代码并创建了“res”,它在右上角的窗口中是一个“数据”,包含 30 个变量的 75008 个观察值。当我尝试查看此内容时,终端显示:“查看错误:'names' 属性 [1] 必须与向量 [0] 的长度相同”。你能建议我能做些什么来克服这个问题吗?我的目标是将每个 parson JSON 字符串视为一行,将每个变量视为一列。然后我可以向下滚动并开始确定我应该保留和丢弃的内容。
    【解决方案2】:

    这是一个 [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\"...
    

    但是

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

    如果您只需要“已经平坦”的数据,请尝试使用 Drill。

    如果您需要嵌套数据并且不想与jsonlite::stream_in() 的取消嵌套或钻头取消嵌套作斗争,那么我建议您使用第一个示例中所述的ndjson,然后切出位您确实需要更易于管理、更整洁的数据框。

    【讨论】:

    • Hrdrmstr - 我不知道如何将他的转换为 .json.gz。我通过将名称调整为 .txt 文件来运行它。将其更改为 .json.gz 文件有什么好处,如果有,我该如何转换?另外,现在我可以看到数据了,我只想选择特定的特征。您有什么方法可以推荐这样做吗?
    • 转换并不重要(它只是节省空间并可以加快解析速度)。您需要找到一个gzip 实用程序(我将假设您在 Windows 上,虽然我知道 Windows,但它意味着要弄清楚将您发送到哪个位置以获取 gzip,而不是仅将您指向内置的-in 更健全/更好的操作系统中的实用程序)。现在您有了一个数据框,只需像使用任何数据框一样选择列即可。
    猜你喜欢
    • 2023-03-12
    • 1970-01-01
    • 2017-10-08
    • 1970-01-01
    • 1970-01-01
    • 2020-10-02
    • 2017-02-03
    • 1970-01-01
    • 2020-09-30
    相关资源
    最近更新 更多