Lapply with "$" Function

How to use lapply or a family of the apply function for calling a function within a function in R?

To avoid confusion, it is better to have anonymous function call

lapply(z, function(x) hrat(x, drat))

How to use lapply with a function that requires a vector as an argument

lapply takes a list as its first argument and a function as its second. Optional arguments for the function can be added as additional arguments to lapply.

By using match(c(1,3), k), you are calling match on c(1, 3) and your list k. What you want to do is to pass a function to lapply that will take a vector x as argument and return match(c(1, 3), x). lapply will then execute this function on each element of your list k.

This is how you should use lapply:

k <- list(c(2,0,2,1),c(3,0,2,0),c(0,1,2,0))
lapply(k, function(x) match(c(1,3), x))
# [[1]]
# [1] 4 NA
#
# [[2]]
# [1] NA 1
#
# [[3]]
# [1] 2 NA

lapply with $ function

For the first example, you can just do:

lapply(dflist, `$.data.frame`, "a")

For the second, use the slot() accessor function

lapply(mylist, "slot", "tab")

I'm not sure why method dispatch doesn't work in the first case, but the Note section of ?lapply does address this very issue of its borked method dispatch for primitive functions like $:

 Note:

[...]

For historical reasons, the calls created by ‘lapply’ are
unevaluated, and code has been written (e.g., ‘bquote’) that
relies on this. This means that the recorded call is always of
the form ‘FUN(X[[i]], ...)’, with ‘i’ replaced by the current
(integer or double) index. This is not normally a problem, but it
can be if ‘FUN’ uses ‘sys.call’ or ‘match.call’ or if it is a
primitive function that makes use of the call. This means that it
is often safer to call primitive functions with a wrapper, so that
e.g. ‘lapply(ll, function(x) is.numeric(x))’ is required to ensure
that method dispatch for ‘is.numeric’ occurs correctly.

using lapply for a function on a matrix with columns as elements in R

Here are several ways. You do not need apply because R is vectorized:

with(df, a*2+x+y-z)
# [1] 5 9 12 15

with(df, sumfunc(a,x,y,z))
# [1] 5 9 12 15

If you really want to use apply):

apply(df, 1, function(x) sumfunc(x[1], x[2], x[3], x[4]))
# [1] 5 9 12 15

Applying a Function to a Data Frame : lapply vs traditional way

When working within a data.frame you could use apply instead of lapply:

x <- seq(1, 10,0.1)
y <- seq(1, 10,0.1)
data_frame <- expand.grid(x,y)
head(data_frame)
some_function <- function(x,y) { return(x+y) }

data_frame$new_column <- apply(data_frame, 1, \(x) some_function(x["Var1"], x["Var2"]))
head(data_frame)

To apply a function to rows set MAR = 1, to apply a function to columns set MAR = 2.

lapply, as the name suggests, is a list-apply. As a data.frame is a list of columns you can use it to compute over columns but within rectangular data, apply is often the easiest.

If some_function is written for that specific purpose, it can be written to accept a single row of the data.frame as in

x <- seq(1, 10,0.1)
y <- seq(1, 10,0.1)
data_frame <- expand.grid(x,y)
head(data_frame)

some_function <- function(row) { return(row[1]+row[2]) }

data_frame$yet_another <- apply(data_frame, 1, some_function)
head(data_frame)

Final comment: Often functions written for only a pair of values come out as perfectly vectorized. Probably the best way to call some_function is without any function of the apply-familiy as in

some_function <- function(x,y) { return(x + y) }
data_frame$last_one <- some_function(data_frame$Var1, data_frame$Var2)

Why does this lapply() function applied to a dataframe not produce the same results as its for-loop equivalent?

To make your lapply code work just replace <- with <<-:

DF_1[row, column] <<- DF_1[row, column] + val

Please see ?assignOps for more info.

However, again I wouldn't recommend lapply in this case (<<- should be avoided in general)

Here is a data.table approach:

library(data.table)

DT <- setDT(data.frame(
ID = c(1,1,1,2,2,2,3,3,3),
Period = c(1, 2, 3, 1, 2, 3, 1, 2, 3),
Values = c(5, 10, 15, 50, 2, 4, 3, 6, 9),
Flags = c("X1","X0","X2","X0","X2","X0", "X2","X1","X1")
))

unique_flags <- unique(DT$Flags)
all_flags <- setDT(expand.grid(list(first_flag = unique_flags, last_flag = unique_flags)))

resultDT <- dcast(
data = DT[, .(first_flag = first(Flags), last_flag = last(Flags), first_value = first(Values)), by = ID][
all_flags, on = c("first_flag", "last_flag")],
last_flag ~ first_flag,
fun.aggregate = sum,
value.var = "first_value"
)

for (col_i in seq_len(ncol(resultDT))){
set(resultDT, which(is.na(resultDT[[col_i]])), col_i, 0)
}
print(resultDT)

Result:

   last_flag X0 X1 X2
1: X0 50 0 0
2: X1 0 0 3
3: X2 0 5 0


# step by step ------------------------------------------------------------
library(data.table)

DT <- setDT(data.frame(
ID = c(1,1,1,2,2,2,3,3,3,4,4,4),
Period = c(1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3),
Values = c(5, 10, 15, 50, 2, 4, 3, 6, 9, 3, 6, 9),
Flags = c("X1","X0","X2","X0","X2","X0", "X2","X1","X1", "X2","X1","X1")
))

unique_flags <- unique(DT$Flags)
all_flags <- setDT(expand.grid(list(first_flag = unique_flags, last_flag = unique_flags)))

resultDT <- DT[, .(first_flag = first(Flags), last_flag = last(Flags), first_value = first(Values)), by = ID] # find relevant flags
resultDT <- resultDT[all_flags, on = c("first_flag", "last_flag")] # merge all combinations
resultDT <- dcast(resultDT, last_flag ~ first_flag, fun.aggregate = sum, value.var = "first_value") # dcast
for (col_i in seq_len(ncol(resultDT))){
set(resultDT, which(is.na(resultDT[[col_i]])), col_i, 0)
}
print(resultDT)

trouble getting Lapply with on-the-fly function to run correctly

When you lapply through a data.frame, you are iterating through its columns, so you just apply something similar to what you have in apply, without the margin argument:

pros.dat = data.frame(matrix(rnorm(100*4),ncol=4),ind=rbinom(100,1,0.5))
lapply(pros.dat[,-5],function(i)t.test.by.ind(i,pros.dat[,5]))


Related Topics



Leave a reply



Submit