Не удается повторно привязать фрейм данных к пустому фрейму данных

#r #rbind

#r #rbind

Вопрос:

Я изучаю R Studio, и это для проекта, над которым я работаю. Я использую Marvel API, чтобы получить список всех персонажей во вселенной, используя цикл for для многократного вызова API. Их API ограничивает вас 100 результатами / вызовом, поэтому я повторяю и устанавливаю смещение для каждого цикла.

Мой код работал последние несколько дней, однако, когда я загрузился сегодня и попытался извлечь данные, я получаю сообщение об ошибке: «Ошибка в rbind(deparse.level, …): недопустимый аргумент списка: все переменные должны иметь одинаковую длину»

Вот код, который я запускаю:

 MarvelUniverse = data.frame()
y = 1
offset = c(0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400)
for(x in offset){
  partialUrl = "https://gateway.marvel.com:443/v1/public/characters?ts=1amp;apikey={apiKey}amp;hash={hash}amp;limit=100amp;offset="  
  url = paste(partialUrl, offset, sep="")
  call = httr::GET(url[y])
  query = httr::content(call, as="raw")
  name = jsonlite::fromJSON(rawToChar(query))
  df = flatten(as.data.frame(name))
  MarvelUniverse = rbind(df, MarvelUniverse)
  y = y   1
}
  

Поскольку раньше я привязывался к пустому фрейму данных, я не понимаю, почему я мог использовать эту функцию раньше, но сейчас она не работает? Я заметил, что df теперь он содержит 1618 элементов, в то время как до разрыва он содержал ~ 1498. name Список по-прежнему содержит большой список из 7 элементов, так что, похоже, это то же самое.

РЕДАКТИРОВАТЬ Я обнаружил, что если я удалю flatten from df = flatten(as.data.frame(name)) , вызов будет выполняться на первой итерации цикла, но теперь я столкнулся с проблемой дублирования row.names . Пытаюсь установить для них значение NULL, но, к сожалению, пока безуспешно.

Комментарии:

1. Почему бы не сохранить ответы GET в виде списка, а затем связать все это вместе в конце, например, с dplyr::bind_rows помощью or Reduce amp; rbind ?

Ответ №1:

Несколько предложений:

  • Не rbind() используйте фреймы данных по одному за раз в цикле — это классический анти-шаблон. Это называется «выращивание объекта» и является 2-м кругом ада в R Inferno. Это очень неэффективно. Скорее, вы должны поместить все свои фреймы данных в список, и rbind все сразу в конце.

  • Вы используете две переменные цикла в одном цикле: x и y . x это тот, который указан в for() , и y вы отслеживаете его вручную. Это может привести к ошибкам — просто используйте одну циклическую переменную (почти всегда лучше, чтобы циклическая переменная превышала 1, 2, 3, …, n)

Для решения этих проблем я бы попробовал этот код:

 MarvelUniverseList = list()
offset = c(0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400)
for(i in seq_along(offset)){
  partialUrl = "https://gateway.marvel.com:443/v1/public/characters?ts=1amp;apikey={apiKey}amp;hash={hash}amp;limit=100amp;offset="  
  url = paste(partialUrl, offset[i], sep="")
  call = httr::GET(url[i])
  query = httr::content(call, as="raw")
  name = jsonlite::fromJSON(rawToChar(query))
  MarvelUniverseList[[i]] = flatten(as.data.frame(name))
}

## combine at end
MarvelUniverse = do.call(rbind, MarvelUniverseList)

## more efficient and flexible version from dplyr
MarvelUniverse = dplyr::bind_rows(MarvelUniverseList)
  

Конечно, без ключа API я не могу это протестировать или посмотреть, в чем ваши проблемы. dplyr::bind_rows немного более гибкий, чем rbind , поэтому он может решить вашу проблему. Но этот подход также имеет то преимущество, что, если возникает проблема с объединением фреймов данных, у вас есть отдельные фреймы данных, сохраненные в списке, и вы можете проверять / отлаживать / исправлять их, чтобы их можно было объединить.

Комментарии:

1. Спасибо за эту очень глубокую разбивку. Это успешно переносит все данные в список для меня. Я знаю, что раньше, когда я передавал его как фрейм данных, и он работал, он сохранял ~ 38 переменных в качестве заголовков столбцов — есть ли простой способ повторно собрать фрейм данных из списка? Прошу прощения, если это очень элементарный вопрос.

2. Каждый элемент списка является фреймом данных, и последние две строки кода, которые я показываю, — это способы объединения этих отдельных фреймов данных в один фрейм данных.

3. Я обнаружил, где я потерпел неудачу — нужно было углубиться в возвращаемый массив, чтобы получить конкретный список, который я искал. Все данные были объединены в фрейм данных, где это было очень беспорядочно. Я извлек две нужные мне переменные со всеми связанными с ними элементами. Еще раз спасибо за вашу помощь, Грегор Томас.