2016-07-17 115 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) 

編輯:

上述解決方案沒有奏效。作爲替代我會用NA替換NULL值:

# 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'來檢查它的代碼 - 它與你正在做的事情有些類似 - 將數據列出,然後將其排列到合適的數組中。適用於您的情況,因爲每個子列表具有相同的長度。請參閱:「長度(l2)」(即使爲NULL)。如果長度不同,可能無法工作。 –

+0

@ user3614648我明白了。也許你可以詳細說明什麼是不正確的,或添加一個簡單的情況下,這不適合你? –

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有一個不正常的長度,但如果你想拯救這些行,可以通過添加另一行來填充缺少的值並使用佔位符。

最後,不要忘記第一行是一個標題,所以你可以把它寫到你的data.frame的colnames

+0

這是識別列表中有問題的元素的有用黑客手段。這不是問題本身的答案,但我會贊成,因爲它有幫助。 注意:當對象返回時,爲什麼變量名會出現在第一行(在我自己的應用程序中,我已經爲此自動修復)。 – user3614648