#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
помощью orReduce
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. Я обнаружил, где я потерпел неудачу — нужно было углубиться в возвращаемый массив, чтобы получить конкретный список, который я искал. Все данные были объединены в фрейм данных, где это было очень беспорядочно. Я извлек две нужные мне переменные со всеми связанными с ними элементами. Еще раз спасибо за вашу помощь, Грегор Томас.