Анализ неструктурированных данных - добавление строк с несуществующими строками значений в набор данных

Я пытаюсь создать набор данных из неструктурированных данных. Необработанные данные - это серия файлов json, каждый из которых содержит информацию об одном элементе данных (например, каждый файл становится строкой в ​​окончательных данных). Я просматриваю jsons с помощью jsonlite, чтобы превратить каждый в огромный вложенный список. Вся эта операция разваливается из-за, казалось бы, простой проблемы:

Мне нужно добавить строки к моим данным, где некоторые элементы не существуют.

Исходные данные выглядят так:

jsn1 <- list(id='id1', col1=1, col2='A', col3=11)
jsn2 <- list(id='id2', col1=2, col2='B', col3=12)
jsn3 <- list(id='id3', col2='C', col3=13)
jsn4 <- list(id='id4', col1=3, col3=14)

Структура, к которой я пытаюсь добраться, такова:

df <- data.frame(id=c('id1','id2','id3','id4'),
                 col1=c(1,2,NA,4),
                 col2=c('A','B','C',NA),
                 col3=c(11,12,13,14))

> df
   id col1 col2 col3
1 id1    1    A   11
2 id2    2    B   12
3 id3   NA    C   13
4 id4    4 <NA>   14

Мой подход заключается в следующем:

#Collect the json names in a vector
files=c('jsn1','jsn2','jsn3','jsn4')

#Initialize the dataframe with the first row filling in any missing values.  
#I didn't do this at first, but it seems helpful.
df1=data.frame(id=jsn1$id,
     col1=jsn1$col1,
     col2=jsn1$col2,
     col3=jsn1$col3,
     stringsAsFactors=F)

#Create a loop to loop through the files extracting the values then add them to a dataframe.
for (i in 2:length(files)) {
    a <- get(files[i])
    new.row <- list(id=a$id,
              col1=a$col1,
              col2=a$col2,
              col3=a$col3) 
    df1 <- rbind(df1,b)
}

Однако это не работает, потому что df1 <- rbind(df1,new.row) требует, чтобы столбцы были одинаковой длины. Я пробовал df1 <- rbind.fill(df1,new.row), rbindlist(list(df1,new.row),use.names=T,fill=T) и df[nrow(df1) +1,names(new.row)] <- new.row. И прочтите это и this среди других.

Большинство ответов можно добавить к фрейму данных, заранее «зная», какие столбцы будут нулевыми или не нулевыми. Затем построим df без этих столбцов и добавим его с заливкой. Это не сработает, так как я не знаю, какие столбцы будут присутствовать заранее. Недостающие в настоящее время заканчиваются 0 элементами, что является корнем проблемы, но мне нужно проверить, присутствуют ли они. Кажется, что должен быть простой способ справиться с этим либо «при чтении», либо в rbind, но я не могу этого понять.

Потенциально существуют сотни столбцов и миллионы строк (хотя сейчас 10 и 100). Файлы jsons велики, поэтому чтение их всех в памяти / обращение к спискам каким-то образом, вероятно, невозможно с реальными данными. Решение с использованием data.table, вероятно, было бы идеальным. Но любая помощь приветствуется. Спасибо.


person user3055034    schedule 28.09.2015    source источник


Ответы (3)


Ты мог бы сделать

data.table::rbindlist(mget(ls(pattern = "jsn[1-4]")), fill = TRUE)
#     id col1 col2 col3
# 1: id1    1    A   11
# 2: id2    2    B   12
# 3: id3   NA    C   13
# 4: id4    3   NA   14

Здесь mget(ls(pattern = "jsn[1-4]")) - это более программный способ собрать списки из глобальной среды, соответствующие шаблону jsn, за которым следуют числа 1-4. Это то же самое, что и list(jsn1, jsn2, jsn3, jsn4), за исключением того, что у него есть имена. Вы могли бы так же легко сделать

rbindlist(list(jsn1, jsn2, jsn3, jsn4), fill = TRUE)

Метод ls() будет лучше, если у вас будет намного больше jsn* списков.

person Rich Scriven    schedule 28.09.2015

Вы хотите rbind.fill от plyr. Сначала вам нужно преобразовать все свои списки в фреймы данных (здесь используется lapply(mylists, as.data.frame)), затем вы можете использовать rbind.fill, чтобы связать их и заполнить недостающие строки с NA:

library(plyr)
rbind.fill(lapply(list(jsn1, jsn2, jsn3, jsn4), as.data.frame))

   id col1 col2 col3
1 id1    1    A   11
2 id2    2    B   12
3 id3   NA    C   13
4 id4    3 <NA>   14
person jeremycg    schedule 28.09.2015

Я собираюсь вернуться, потому что я понял это и хочу поделиться, если кто-то еще столкнется с этой проблемой. Проблема заключалась в том, что при чтении значений, которых нет в цикле, в моем списке создавались нули, которые мешали работе rbindlist и rbind.fill.

Чтобы быть более конкретным, я делал это:

new.row <- list(id=a$id,
              col1=a$col1,
              col2=a$col2,
              col3=a$col3) 

когда a$col2 не было в списке, прочитанном из json. Это приводит к тому, что new.row$col2 становится NULL, и вы не можете использовать new.row в rbindlist или rbind.fill. Однако все, что мне нужно было сделать, это удалить эти нули из списка вот так

plyr::compact(new.row)

Источник

до этого с помощью rbindlist. Оба ответа были полезны, поскольку показали мне, что rbindlist или rbind.fill будут работать без нулевых значений.

person user3055034    schedule 29.09.2015