Lapply to Add Columns to Each Dataframe in a List
Use Map
. It is short for mapply(..., SIMPLIFY = FALSE)
as suggested by Ari.
df1 <- data.frame(x = runif(3), y = runif(3))
df2 <- data.frame(x = runif(3), y = runif(3))
dfs <- list(df1, df2)
years <- list(2013, 2014)
Map(cbind, dfs, year = years)
# [[1]]
# x y year
# 1 0.8843945 0.6285246 2013
# 2 0.8400041 0.1369520 2013
# 3 0.4398870 0.4660476 2013
#
# [[2]]
# x y year
# 1 0.4153315 0.5831114 2014
# 2 0.9685105 0.2398060 2014
# 3 0.9507591 0.7585670 2014
Adding a column to a list of dataframe with lapply
Try assigning the result of the lapply call to an object; in this case, you can assign back to the originating list of dataframes
dat.s<-lapply(...)
Using lapply over a list and adding a column with data frame name
We can loop through names
of sample_list instead of looping through the list
lapply(names(sample_list), function(x) {
sample_list[[x]] %>%
filter_at(vars(1),~. >= 20) %>%
mutate(groupName = x)
})
Update Sep-2021
cleaner way using purrr::map
purrr::map(names(sample_list), ~sample_list[[.x]] %>%
filter_at(vars(1),~. >= 20) %>%
mutate(groupName = .x)
)
Create new column in each dataframe of list and fill with string from character vector based on position (R)
You can also try creating directly mycol
with mapply()
:
#Data
dfs<-list(mtcars[,1:4], iris[,1:4])
z <- c("red", "blue")
#Code
L <- mapply(function(x,y) {x$mycol<-y;return(x)},x=dfs,y=z,SIMPLIFY = F)
Add new column name to a list of data frames from a part of the file name using lapply
Name the list of filenames using setNames()
, then use the .id
argument in bind_rows()
, which adds a column containing list names.
library(tidyverse)
library(readxl)
files <- list.files(path ="Users/Desktop/week", pattern = "*.xlsx", full.names= T) %>%
setNames(nm = .) %>%
lapply(read_excel, sheet =4, skip =39) %>%
bind_rows(.id = "Week") %>%
mutate(Week = str_extract(Week, "wk\\d+"))
You could also combine the iteration and row-binding steps using purrr::map_dfr()
:
files <- list.files(path ="Users/Desktop/week", pattern = "*.xlsx", full.names= T) %>%
setNames(nm = .) %>%
map_dfr(read_excel, sheet = 4, skip = 39, .id = "Week") %>%
mutate(Week = str_extract(Week, "wk\\d+"))
R: add new column to a list of data frames with lapply
It's because my_list[[1]]["SubCat"] <- as.character("")
doesn't return anything, so, after the expression is evaluated you have NULL
as data and the cbind
process cannot execute it accordingly. Also, lapply
will execute your function for each and every data frame
in your list, so your command should like as follows:
vec.1 <- c(1, 2)
vec.2 <- c(2, 3)
df.1 <- data.frame(vec.1, vec.2)
df.2 <- data.frame(vec.2, vec.1)
my_list <- list(df.1, df.2)
## This is the correct use of lapply for your list
my_list <- lapply(my_list, cbind, SubCat = c(""))
my_list
[[1]]
vec.1 vec.2 SubCat
1 1 2
2 2 3
[[2]]
vec.2 vec.1 SubCat
1 2 1
2 3 2
EDIT: lapply
takes a list as argument and a function to apply in each and every one of the list's elements. However, cbind
requires two arguments. The additional arguments are passed with lapply
. Now, you may notice that the SubCat
vector consists of one null string; that is OK, because R repeats that vector as many times as needed.
EDIT #2:
Hmm, this error is probably coming from the empty data.frames, which I didn't take into account. You could do this to solve your problem (I didn't take into account that a vector cannot repeat itself zero times):
my_list <- lapply(my_list, function(df){
if (nrow(df) > 0)
cbind(df, SubCat = c(""))
else
cbind(df, SubCat = character())
})
Added by the author of the question:
It is OK, to complete a column with blanks("") according to the
other columnsSubCat = c("")
. But, if you have an empty data frame,
you need to start a new column with:SubCat = character()
, which is a zero length column.
Adding columns to multiple dataframes in a list in R
Based on the comments, 'Y' is created as a list
from split
ting the 'Z' by the 'site' column
Y <- split(Z, Z$site)
Y.nmds <- lapply(Y, function(x) metaMDS(x[-(1:4)]))
Now, we can use Map
to loop over the corresponding list
elements of 'Y.nmds' with 'Y' to create the columns
lst1 <- Map(function(nmd, dat, site) {
dat1 <- as.data.frame(scores(nmd))
transform(dat1, site = site,
reserve_status = dat$reserve_status,
year = dat$year)
}, Y.nmds, Y, names(Y))
-output
lst1
#$AYUNGON
# NMDS1 NMDS2 site reserve_status year
#1 -0.5405524 -0.208839893 AYUNGON Inside 2012
#2 -0.4679394 -0.127144729 AYUNGON Inside 2012
#3 -0.4470720 -0.035047840 AYUNGON Inside 2012
#4 -0.3723951 -0.004604424 AYUNGON Inside 2012
#5 -0.3527766 0.062692135 AYUNGON Inside 2012
#6 -0.3214464 0.117212445 AYUNGON Inside 2014
#7 -0.2585269 0.118163340 AYUNGON Inside 2014
#8 -0.2434562 0.173341542 AYUNGON Inside 2014
#9 0.8334110 -0.008478317 AYUNGON Inside 2014
#10 0.6918728 -0.048824777 AYUNGON Inside 2014
#11 0.5889373 0.008377321 AYUNGON Inside 2015
#12 0.4882185 -0.028821935 AYUNGON Inside 2015
#13 0.4017254 -0.018024867 AYUNGON Inside 2015
#$BINDOY
# NMDS1 NMDS2 site reserve_status year
#14 -0.4973781 0.0312765162 BINDOY Inside 2015
#15 -0.4901276 -0.0008288276 BINDOY Inside 2015
#16 -0.4816021 -0.0282379296 BINDOY Inside 2016
#17 0.1943789 0.0619863596 BINDOY Inside 2016
#18 0.1924750 0.0348895563 BINDOY Inside 2016
#19 0.1876516 0.0165441678 BINDOY Inside 2016
#20 0.1853833 0.0016281922 BINDOY Inside 2016
#21 0.1832898 -0.0126894179 BINDOY Inside 2017
#22 0.1774036 -0.0243657601 BINDOY Inside 2017
#23 0.1750507 -0.0370687919 BINDOY Inside 2017
#24 0.1734749 -0.0431340651 BINDOY Inside 2017
R use of lapply() to populate and name one column in list of dataframes
A full R base approach without using loops
> l<-list(a=c(1,2,3),b=c(4,5,6,7))
> data.frame(grp=rep(names(l), lengths(l)), num=unlist(l), row.names = NULL)
grp num
1 a 1
2 a 2
3 a 3
4 b 4
5 b 5
6 b 6
Add a new column to each df in a list of dfs using apply function
The function week_no
is not vectorised so you would need some kind of loop to iterate over each value after strsplit
. In the for
loop you use sapply
, so we can use the same here.
lapply(mapp_dfs, function(x) cbind(x,
week_nums = sapply(as.Date(unlist(strsplit(x$Timestamp, "T"))[c(TRUE,FALSE)]), week_no)))
#$l1
# Timestamp Value Q.code week_nums
#1 1993-08-30T00 13.53 1 36
#2 2002-01-16T00 1.55 2 3
#3 2010-01-13T00 5.63 3 3
#4 2016-11-08T00 7.32 4 46
#5 2019-05-13T00 7.89 5 20
#$l2
# Timestamp Value Q.code week_nums
#1 1994-07-10T00 13.53 1 28
#2 2003-01-26T00 1.55 1 4
#3 2011-01-13T00 5.63 3 3
#4 2016-11-08T00 9.31 4 46
#5 2019-05-23T00 5.63 1 21
#$l3
# Timestamp Value Q.code week_nums
#1 1995-08-30T00 1.36 2 36
#2 2004-01-16T00 5.63 2 3
#3 2012-01-13T00 5.63 5 3
#4 2013-11-08T00 7.32 4 45
#5 2019-06-03T00 5.22 4 23
Related Topics
How to Access Global/Outer Scope Variable from R Apply Function
How to Change the Format of an Individual Facet_Wrap Panel
Convert Latitude and Longitude Coordinates to Country Name in R
Assigning by Reference into Loaded Package Datasets
Sequence Length Encoding Using R
Different Colors for Each Bar in Stacked Bar Graph - Base Graphics
As.Date(As.Posixct()) Gives the Wrong Date
Is There a Fast Estimation of Simple Regression (A Regression Line with Only Intercept and Slope)
How to Create a Bar Plot for Two Variables Mirrored Across the X-Axis in R
Should I Avoid Programming Packages with Pipe Operators
Remove Unused Factor Levels from a Ggplot Bar Plot
Ggplot: Order Bars in Faceted Bar Chart Per Facet
Identifying Where Value Changes in R Data.Frame Column