2016-07-17 5 views
0

Я пытаюсь использовать API переписи для загрузки определенных таблиц и сохранения их в кадрах данных. Мне удалось загрузить данные. Я собираю соответствующий URL для вызова, а затем использовал пакет «rjson» для чтения URL-адреса в списке. Например:R: Преобразование списка списков в фрейм данных (данные переписи)

library(rjson)  

get <- c("B19081_002M")          # create vector of vars 
datafile <- "http://api.census.gov/data/2009/acs5?"   # ACS 05-09 
get <- paste0("get=NAME,", paste(get, collapse = ','))  # variables 
geo <- "for=county:*"          # all counties 
api_key <- "key=KEYHERE"          # API key 
url <- paste0(datafile, paste(get, geo, api_key, sep = "&")) # creates url 
data <- fromJSON(file = url)         # read into R 

# To see an example of a problematic observation 
# (this should return "Hinsdale County, Colorado") 

data[[273]] 

Однако у меня возникают трудности с преобразованием этого в кадр данных. Функция fromJSON() создает объект списка. В большинстве случаев элементы объекта списка являются векторами chr для каждой пространственной единицы (например, графства в приведенном выше примере), а вектор содержит информацию таблицы и связанную метадату. В этом случае я использую подход в приведенном ниже рабочем примере для преобразования списка в кадр данных, где каждая строка представляет собой другую пространственную единицу, и каждый столбец представляет собой другую переменную.

# Create fake data 
x1 <- seq(1:5) 
x2 <- rep(5,5) 
l1 <- list(x1,x2) 

# Convert to df 
cols_per_row <- length(unlist(l1[1])) 
test1 <- data.frame(matrix(unlist(l1), byrow = TRUE, ncol = cols_per_row)) 

print(test1) # success! 

X1 X2 X3 X4 X5 
1 1 2 3 4 5 
2 5 5 5 5 5 

Но когда я использую тот же подход с прейскурантной-в-списке объекта (который возникает потому, что я в том числе различных таблиц из API), я получаю сообщение об ошибке:

# Create fake data 
x1 <- seq(1:5) 
x2 <- rep(5,5) 
x3 <- list(1,2,3,4,NULL) 
l2 <- list(x1,x2,x3) 

# Produces an error 
cols_per_row <- length(unlist(l2[1])) 
test2 <- data.frame(matrix(unlist(l2), byrow = TRUE, ncol = cols_per_row)) 

Warning message: 
In matrix(unlist(l2), byrow = TRUE, ncol = cols_per_row) : 
data length [14] is not a sub-multiple or multiple of the number of columns [5] 

ли кто-нибудь есть решение для этого?

  • Я заметил, что под-списки появляются только в тех случаях, когда одна из переменных имеет значение NULL.
  • В тех случаях, когда элемент основного списка также является списком, суб-список имеет длину, равную длине векторов для элемента основных списков, являющихся векторами.

Примечания

  • мне не нужно использовать fromJSON и приветственные альтернативы, которые могли бы сделать это проще.
  • Я не хочу использовать пакет «acs» для этого, поэтому, пожалуйста, не предлагайте его использовать. Я пытаюсь научиться справляться с этой проблемой.
+0

'as.data.frame (do.call (cbind, l2)) 'будет типичным (но не большим, вы потеряете типы) способом. 'purrr' полезен для работы со списками; вы можете сделать что-то вроде 'l2%>% setNames (make.names (seq_along (.)))%>% at_depth (2, ~ .x% ||% NA)%>% map_df (unlist)', хотя это может не самая изящная версия. – alistaire

ответ

0

Может быть, это то, что вы после:

simplify2array(l2) 

EDIT:

выше решение не работает. В качестве альтернативы я бы заменить NULL значения с NA:

# Function to replace NULL values to NA values inside a list 
listNull2Na <- function(l) sapply(l, function(x) ifelse(is.null(x), NA, x)) 

# Substitute NULL values in your list and get matrix: 
l2 <- sapply(l2, listNull2Na) 
+0

Я не думаю, что он работает с реальными данными. По крайней мере, это не было в моем тесте (в результате получилась странная форма - отрезали одно измерение и дали 3222 колонки). Исправьте меня, если я ошибаюсь, OP. –

+0

@ Hack-R грустно У меня нет реальных данных, поэтому не могу проверить. Я работаю над данными о игрушке, которые предоставил OP ... @ user3614648 Эта функция используется внутренне с помощью 'sapply()' мало информации об этом. Но мы можем проверить его код, набрав 'simplify2array' - он делает нечто похожее на то, что вы делаете, - не поддерживает данные, а затем упорядочивает их в подходящий массив. Работает в вашем случае, потому что каждый подсписчик имеет одинаковую длину. Смотрите: 'lengths (l2)' (даже с NULL). Не может работать, если длина была другой. –

+0

@ пользователь3614648 посмотрю. Может быть, вы можете уточнить, что является неправильным или добавить простой случай, когда это не работает для вас? –

1

Я дам тебе хак с помощью реального запроса:

tmp <- data.frame(matrix(ncol=4)) 

for(i in 1:length(data)){ 
    if(length(t(unlist(data[i]))) == 4){ 
    tmp[i,] <- t(unlist(data[i])) 
    } else{ 
    cat("Row number ", i, "has an abnormal length \n") 
    } 
} 
Row number 273 has an abnormal length 
Row number 550 has an abnormal length 
Row number 1900 has an abnormal length 
Row number 2733 has an abnormal length 
Row number 2737 has an abnormal length 
Row number 2753 has an abnormal length 
head(tmp) 
1        NAME B19081_002M state county 
2  Aleutians East Borough, Alaska  8469 02 013 
3 Aleutians West Census Area, Alaska  7691 02 016 
4  Anchorage Municipality, Alaska   920 02 020 
5   Bethel Census Area, Alaska  2414 02 050 
6  Bristol Bay Borough, Alaska  9635 02 060 

Только 6 из> 3000 имел ненормальную длину, но если вы хотите спасти эти строки, это можно сделать, добавив еще одну строку, чтобы заполнить недостающее значение с помощью заполнителя.

Наконец, не забывайте, что первая строка является заголовком, поэтому вы можете записать ее на colnames вашего data.frame.

+0

Это полезный взлом для определения проблемных элементов списка. Это не ответ на проблему как таковую, но я буду поддерживать ее, поскольку она полезна. Примечание: это также несколько озадачивает, почему имена переменных появляются в первой строке (в моем собственном приложении я автоматизировал исправление для этого), когда объект возвращается. – user3614648

 Смежные вопросы

  • Нет связанных вопросов^_^