Разбор массивов JSON из файла.txt в R - несколько больших файлов

Недавно я загружал большое количество твитов из Twitter. Моя отправная точка - около 400 .txt файлов, содержащих идентификаторы твитов. После запуска инструмента твиты извлекаются из Twitter с использованием идентификаторов твитов, и для каждого файла.txt, который у меня был, с большим списком идентификаторов твитов, я получаю очень большой файл.txt, содержащий строки JSON. Каждая строка 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): невозможно найти унаследованный метод для функции "fromJSON" для подписи "список", "отсутствует" "

Моя другая попытка:

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

Этот код, кажется, анализирует только первую строку JSON в файле. Я говорю это потому, что когда я пытаюсь выбрать "текст" или "id_str", я получаю только один экземпляр. Стоит также отметить, что "json_file" - это большой список размером 52,7 МБ, тогда как исходный файл составляет 335 МБ.

2 ответа

Попробуйте 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, что может быть удобнее.

Это [n]ewline [d]elimited [json] (ndjson) файл, который был сделан специально для ndjson пакет. Упомянутая упаковка очень значительно быстрее, чем jsonlite::stream_in() и создает "абсолютно плоский" фрейм данных. Эта последняя часть ("абсолютно плоская") не всегда нужна людям, так как она может создать очень широкую структуру (в вашем случае 1012 столбцов, поскольку она расширяет все вложенные компоненты), но вы быстро получаете то, что вам нужно, без необходимости ничего не делай сам.

Выход из str() или даже glimpse() слишком велик, чтобы показать здесь, но это то, как вы его используете.

Обратите внимание, что я переименовал ваш файл с .json.gz обычно это то, как хранится ndjson (и мой пакет может обрабатывать файлы gzip'd 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() или борясь с дрелью unnesting, то я бы предложил использовать ndjson как было отмечено в первом примере, а затем разделите нужные фрагменты на более удобные и аккуратные кадры данных.

Другие вопросы по тегам