2

I've got a giant lapply running to download a file of data. But it seems clumsy. But mapply does not seem right, as I don't want all state/county combinations. I hear good things about map(). Can anyone furnish an example of how I might use purrr() command 'map' for the following code?

library(tidycensus)
library(sf)
mykey<-"youhavetogetyourownimafraid"
#variables to test out the function#############
x<-"06"
y<-"073"
z<-"2000"
setwd("N:/Dropbox/_BonesFirst/149_Transit_Metros_BG_StateSplit_by_R")
##################now the actual function#########################
get_Census <- function(x,y,z) {
  name<-paste0("transitmetro_",x,"_",y,"_",z)
  name
  namefile<-get_decennial(geography = "block group",
                variables = "P001001",
                sumfile = "sf1",
                key = mykey,
                state = x, county = y,year = z,
                geometry = TRUE)
  st_write(namefile, paste0(name,".shp")) #tidycensus version of write OGR
}  

#now, for all of them
CO<-c("013")
tibble04_10<-lapply(CO,get_Census,x="04",z="2000")
CO<-c("067","073","113")
tibble06_10<-lapply(CO,get_Census,x="06",z="2000")
CO<-c("005","031","035")
tibble08_10<-lapply(CO,get_Census,x="08",z="2000")
CO<-c("037","053","123")
tibble27_10<-lapply(CO,get_Census,x="27",z="2000")
CO<-c("119")
tibble37_10<-lapply(CO,get_Census,x="37",z="2000")
CO<-c("085","113","121","201")
tibble48_10<-lapply(CO,get_Census,x="48",z="2000")
CO<-c("035") #SLCO, utah
tibble49_10<-lapply(CO,get_Census,x="49",z="2000")
CO<-c("033","053") #King co, Seattle
tibble53_10<-lapply(CO,get_Census,x="53",z="2000")

EDIT

get_Census <- function(x,y,z) {
  name<-paste0("transitmetro_",x,"_",y,"_",z)
  name
  namefile<-get_decennial(geography = "block group",
                          variables = "P001001",
                          sumfile = "sf1",
                          key = mykey,
                          state = x, county = y,year = z,
                          geometry = TRUE)
  st_write(namefile, paste0(name,".shp")) #tidycensus version of write OGR
}  

CO_list <- list(c("013"),
                c("067","073","113"),
                c("005","031","035"),
                c("037","053","123"),
                c("119"),
                c("085","113","121","201"),
                c("035"),
                c("033","053"))

x_list <- c("04", "06", "08", "27", "37", "48", "49", "53")
z_list <- c("2000", "2000", "2000", "2000", "2000", "2000", "2000", "2000")
# BUILD LIST OF OBJECTS
tibble_list <- Map(function(CO, x, z) lapply(CO, function(i) get_Census(i, x, z)), 
                   CO_list, x_list, z_list)
# NAME LIST OF OBJECTS: tibble04_10, tibble06_10, tibble08_10, ...
tibble_list <- setNames(tibble_list, paste0("tibble", x_list, "_10"))
print(tibble_list)

Yields:

Getting data from the 2000 decennial Census Error : Result 1 is not a length 1 atomic vector In addition: Warning messages: 1: '004' is not a valid FIPS code for counties in Georgia
2: '004' is not a valid FIPS code for counties in Georgia
Show Traceback
Rerun with Debug Error in gather_(data, key_col = compat_as_lazy(enquo(key)), value_col = compat_as_lazy(enquo(value)), : unused argument (-NAME)

Mox
  • 511
  • 5
  • 15
  • If there is only change in "CO" and "x", then you could use `map2`, place the "CO" in a `list` i.e.`CO <- list("013", c("067", "073", "113")); map2(CO, list("04", "06"), ~ get_Cenus(x = .y, y = .x, z = "2000"))` – akrun May 10 '18 at 17:43
  • Map2 also part of purrr? – Mox May 10 '18 at 17:44
  • 1
    Is is `map2` that is in purrr – akrun May 10 '18 at 17:48
  • Ok, looks like map2 is no good, as I do need (now) to use both 2000 and 2010 as variables. – Mox May 11 '18 at 15:00

2 Answers2

3

Re-consider base R's apply family, namely Map (wrapper to mapply) and lapply which I hear good things about. Simply build equal length lists to pass into a nested function call.

CO_list <- list(c("013"),
                c("067","073","113"),
                c("005","031","035"),
                c("037","053","123"),
                c("119"),
                c("085","113","121","201"),
                c("035"),
                c("033","053"))

x_list <- c("04", "06", "08", "27", "37", "48", "49", "53")
z_list <- c("2000", "2000", "2000", "2000", "2000", "2000", "2000", "2000")

# BUILD LIST OF OBJECTS
tibble_list <- Map(function(CO, x, z) lapply(CO, function(i) get_Census(i, x, z)), 
                   CO_list, x_list, z_list)

# NAME LIST OF OBJECTS: tibble04_10, tibble06_10, tibble08_10, ...
tibble_list <- setNames(tibble_list, paste0("tibble", x_list, "_10"))

Also, since z_list is redundant being all the same, you can shorten:

tibble_list <- Map(function(CO, x) lapply(CO, function(i) get_Census(i, x, z=2000)), 
                   CO_list, x_list)
Parfait
  • 104,375
  • 17
  • 94
  • 125
  • I fear a nested function call is beyond my current skills. Could you explicate a bit? – Mox May 11 '18 at 01:06
  • Essentially, we nest your `lapply` inside a `Map` call and generalize the parameters into equal length lists. Curious, did you give it a try? A list will output (no longer flooding global environ with many similar tibble*_10 objects). – Parfait May 11 '18 at 01:15
  • I get "Error in mapply(FUN = f, ..., SIMPLIFY = FALSE) : object 'CO_list' not found" – Mox May 11 '18 at 14:51
  • Please see this answer again. Did you assign a *CO_list* (remember case-sensitivity) as beginning shows? Also, you can verify tibble objects within the **one** *tibble_list*. Just `print`/`str` out as needed: `tibble_list$tibble04_10`! – Parfait May 11 '18 at 15:24
  • Hmmm... straight copy on my end in blank R script, replacing your `get_Census(i, x, z)` with `c(i, x, z)` yields no error. Try restarting session, clearing everything. – Parfait May 11 '18 at 17:49
  • Ok, replacing get_Census with c yields no error; running the get_Census on it's own yields no error, trying to combine them results in an error. – Mox May 11 '18 at 21:33
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/170885/discussion-between-mox-and-parfait). – Mox May 11 '18 at 21:39
2

You can use map from purrr to map over a list of your county characteristics. One way to do this is a list of lists, such as:

fips_yrs <- list(
    sl_co = list(x = "49", y = "035", z = 2000),
    king_co = list(x = "53", y = "053", z = 2000)
)

Then map will map over each county, and you can pull out its info by name with [[1]].

map(fips_yrs, ~get_Census(x = .$x[[1]], y = .$y[[1]], z = .$z[[1]]))

FYI, if all you need is the shapefiles, tidycensus uses functions from tigris to download its shapefiles, so you could just call a tigris function directly.

camille
  • 16,432
  • 18
  • 38
  • 60