I'm sorry if it's a duplicate, and for the lack of reproducibility, I'd have to link you the files.
What I'm trying to do is this:
I have a data frame with coordinates and names, let's say
df <- tribble(
~Species, ~lat, ~lon,
"a",42.92991, 11.875801,
"b",42.92991, 11.875801,
"c",43.91278, 3.513611,
"d",43.60851, 3.871755,
"e",39.24373, 9.120478
)
I also have a folder with tifrasters, such as
files <- list.files(path="~/world/", pattern="*.tif$", full.name=TRUE, all.files=TRUE)
Now for each iteration I'd like to:
create a new column on the data frame with the file name
insert in that column the extracted value for the corresponding lat and lon
I've tried using this for loop, and while on paper looks just fine, I don't understand why it outputs to funvar the last result only. I't like it overwrites the result instead of appending it.
If I use a similar loop with mutate and simpler objects, it appends them, so I'm not sure what the problem could be
for(i in files){
fraster<- raster(i)
fname<-gsub(".*//|[.].*", "", i)
funvar<-dplyr::mutate(fundata, !!fname:= raster::extract(fraster, coordinates(data.frame(lat,lon))))
}
Thanks!
The way I solved it is a bit of an hack, but works. I explicitly assign the new column to a data frame, like this.
I'm still notsure why mutate doesn't do that by itself
for(i in files){
fraster<- raster(i)
fname<-gsub(".*//|[.].*", "", i)
funvar<-dplyr::mutate(fundata, !!fname:= raster::extract(fraster, coordinates(data.frame(lat,lon))))
fundata[fname] <- funvar[[fname]]
}
From the info you provide I cannot tell if this will work, but normally you would make a RasterStack and avoid the loop.
library(raster)
# NOTE the order of lon, lat`
xy <- cbind(lon, lat)
s <- stack(files)
e <- raster::extract(s, xy)
If that is not possible, you can do something like this
fundata <- data.frame(xy)
for (f in files){
fraster<- raster(f)
fname <- gsub(".tif$", "", basename(f))
fundata[[fname]] <- raster::extract(fraster, xy)
}
I work with SAS files (sas7bdat = dataframes) and SAS formats (sas7bcat).
My sas7bdat files are in a "data" file, so I can get a list in object files_names.
Here is the first part of my code, working perfectly
files_names <- list.files(here("data"))
nb_files <- length(files_names)
data_names <- vector("list",length=nb_files)
for (i in 1 : nb_files) {
data_names[i] <- strsplit(files_names[i], split=".sas7bdat")
}
for (i in 1:nb_files) {
assign(data_names[[i]],
read_sas(paste(here("data", files_names[i])), "formats/formats.sas7bcat")
)}
but I get some issues when trying to apply function as_factor from package haven (in order to apply labels on my new dataframes and get like SEX = "Male" instead of SEX = 1).
I can make it work dataframe by dataframe like the code below
df_labelled <- haven::as_factor(df, only_labelled = TRUE)
I would like to create a loop but didn't work because my data_names[i] isn't a dataframe and as_factor requires a dataframe in first argument.
I'm quite new to R, thank you very much if someone could help me.
you might want to think about using different data structures, for example you can use a named list to save your dataframes then you can easily loop through them.
In fact you could do everything in one loop, I'm sure there's a more efficient way to do this, but here's an example of one way without changing your code too much :
files_names <- list.files(here("data"))
raw_dfs <- list()
labelled_dfs <- list()
for (file_name in files_names) {
# # strsplit returns a list either extract the first element
# # like this
# df_name <- (strsplit(file_name, split=".sas7bdat"))[[1]]
# # or use something else like gsub
df_name <- gsub(".sas7bdat", '', file_name)
raw_dfs[df_name] <- read_sas(paste(here("data", file_name)), "formats/formats.sas7bcat")
labelled_dfs[df_name] <- haven::as_factor(raw_dfs[[df_name]], only_labelled = TRUE)
}
Thank you in advance for your advice. I am trying to create a new variable over multiple objects in a loop. These new variables are generated by a function.
For example, I have three sets of country-level data:
# Generate Example Data
`enter code here`pop <- data.frame(country=c("US","US","CA","CA","FR","FR"),year=c(1,2,1,2,1,2),value=c(290,300,29,30,50,55))
gas <- data.frame(country=c("US","US","CA","CA","FR","FR"),year=c(1,2,1,2,1,2),value=c(3.10,1.80,4.50,2.50,4.50,2.50))
cars <- data.frame(country=c("US","US","CA","CA","FR","FR"),year=c(1,2,1,2,1,2),value=c(2.1,2.2,1.8,1.9,1.3,1.3))
I want to create a new variable, called “countrycode”, using the countrycode() command in the countrycode package.
I would perform the operation on individual objects like this:
library(countrycode)
pop$ccode <- countrycode(pop$country,"iso2c","cown")
pop$id <- (pop$ccode*10000)+pop$year
But I have a large number of objects. I was hoping to do this over a loop, like this
# Create list of variables
vars <- c("pop","gas","cars")
for (i in vars){
i$ccode <- countrycode(country,"iso2c","cown")
i$id <- (i$ccode*10000)+i$year
}
But that doesn’t work. I’ve been trying to do this using assign() in loops and apply(), but I’m too dense to get my head around how to make this work in my case.
If someone could provide me with an example of how to do this with my own type of data, I’d be very grateful.
Would this work for you?
pop <- data.frame(country=c("US","US","CA","CA","FR","FR"),year=c(1,2,1,2,1,2),value=c(290,300,29,30,50,55))
gas <- data.frame(country=c("US","US","CA","CA","FR","FR"),year=c(1,2,1,2,1,2),value=c(3.10,1.80,4.50,2.50,4.50,2.50))
cars <- data.frame(country=c("US","US","CA","CA","FR","FR"),year=c(1,2,1,2,1,2),value=c(2.1,2.2,1.8,1.9,1.3,1.3))
attachCodes <- function(dframe)
{
df <- dframe
df$ccode <- countrycode(df$country,"iso2c","cown")
df$id <- (df$ccode*10000)+df$year
return(df)
}
tablesList <- list(pop,gas,cars)
tablesList <- lapply(tablesList,attachCodes)
Special thanks to #Pawel for supplying the missing information needed to solve the problem. The solution was:
rm(list=ls())
pop <- data.frame(country=c("US","US","CA","CA","FR","FR"),year=c(1,2,1,2,1,2),value=c(290,300,29,30,50,55))
gas <- data.frame(country=c("US","US","CA","CA","FR","FR"),year=c(1,2,1,2,1,2),value=c(3.10,1.80,4.50,2.50,4.50,2.50))
cars <- data.frame(country=c("US","US","CA","CA","FR","FR"),year=c(1,2,1,2,1,2),value=c(2.1,2.2,1.8,1.9,1.3,1.3))
attachCodes <- function(dframe)
{
df <- dframe
df$ccode <- countrycode(df$country,"iso2c","cown")
df$id <- (df$ccode*10000)+df$year
return(df)
}
names <- list("pop","gas","cars")
for(i in names){
assign(i,attachCodes(get(i)))
}
I've been searching for a while now and can't seem to come up with an answer. I'm just creating a simple function for some statistical data that I'm pulling from a list and manipulating it and create averages and whatnot. The function isn't returning anything though. No errors are being produced and the matrix is being created.
Source:
library(matrixStats)
source("Control_Function.R")
mydata <- read.table("DataSmall.txt")
length <- nrow(mydata)
a<-length/11
#begining control limits
control(mydata)
Control_Function.R
control <- function(arg1){
mat1 <-matrix(unlist(arg1),11,25)
matAverage <-colMeans(mat1)
matSdAv <- colSds(mat1)
sbar <-mean(matSdAv)
xbarbar<-mean(matAverage)
newlist<-list(matAverage, matSdAv, sbar, xbarbar)
return(newlist)
}
Any help would be greatly appreciated.
Thanks
If you just want to see the answers, then you need to add "print" like this:
control <- function(arg1){
mat1 <-matrix(unlist(arg1),11,25)
print(matAverage <-colMeans(mat1))
print(matSdAv <- colSds(mat1))
print(sbar <-mean(matSdAv))
print(xbarbar<-mean(matAverage))
newlist<-list(matAverage, matSdAv, sbar, xbarbar)
return(newlist)
}
If you want to actually save one of those objects to your workspace (not the function environment), then add a <<- like this to the object you want to save (I made the object I wanted to add to the workspace "newlist"):
control <- function(arg1){
mat1 <-matrix(unlist(arg1),11,25)
print(matAverage <-colMeans(mat1))
print(matSdAv <- colSds(mat1))
print(matSdAv)
print(sbar <-mean(matSdAv))
print(xbarbar<-mean(matAverage))
newlist <<- list(matAverage, matSdAv, sbar, xbarbar)
}
i try do add economic data to a shapefile using merge and the 2 digit ISO code as ID. The code looks somewhat like this:
library(maptools)
library(foreign)
library(sp)
library(lattice)
library(shapefiles)
world.shp<-readShapePoly("world_shapefile.shp")
world.shp#data<-merge(world.shp#data, data.frame(country=iso.code.vector, net=country.data.vector), by.x="ISO2", by.y="country", all.x=TRUE, sort=FALSE)
Unfortunately this ruins the order of the .shp file even though i put the sort argument. A plot afterwards shows me that the data does not match the polygons like it should. What am i doing wrong?
i got the world map data from thematicmapping.org
Thanks for your help
Merge will always break the sp object. Here are two ways to merge a dataframe to the sp #data datframe.
shape#data = data.frame(shape#data, OtherData[match(sdata#data$IDS, OtherData$IDS),])
Where; shape is your shape file, IDS is the identifier you want to merge on and OtherData is the dataframe that you want to combine with shape. Note that IDS can be different names in the two datasets but need to actually be the same values (not fuzzy).
Alternatively you can use this function.
join.sp.df <- function(x, y, xcol, ycol) {
x$sort_id <- 1:nrow(as(x, "data.frame"))
x.dat <- as(x, "data.frame")
x.dat2 <- merge(x.dat, y, by.x = xcol, by.y = ycol)
x.dat2.ord <- x.dat2[order(x.dat2$sort_id), ]
x2 <- x[x$sort_id %in% x.dat2$sort_id, ]
x2.dat <- as(x2, "data.frame")
row.names(x.dat2.ord) <- row.names(x2.dat)
x2#data <- x.dat2.ord
return(x2)
}
Where; x=sp SpatialDataFrame object, y=dataframe object to merge with x, xcol=Merge column name in sp object (need to quote), ycol=Merge column name in dataframe object (need to quote)
I found the same problem when using R versions 2.12.x and 2.13.x, but the problem appears to have been resolved in version 2.15.1.
I found a workaround. Not very elegant actually and it takes some time to execute but it works:
world.shp<-readShapePoly("world_shapefile.shp")
net<-rep(NA,length(world.shp#data$NAME))
for(i in 1:length(net))
{
for(j in 1:length(iso.code.vector))
{
if(!is.na(world.shp#data$ISO2[i])){if(world.shp#data$ISO2[i]==iso.code.vector[j]){net[i]=country.data.vector[j]}}
}
}
world.shp#data<-data.frame(world.shp#data, net)