将函数应用于数据框中的每个元素并返回数据框

13

更新:之前,我用paste函数作为示例,而不是任意的myFun函数。那个问题稍微容易一些,因为paste实际上可以操作向量,而myFun不能。

我想把自己的函数逐个应用到数据框中的每个元素,并获得修改后的数据框作为返回值。

示例:

> df <- data.frame(c(1,2,3), c(2,3,4))
> df
  c.1..2..3. c.2..3..4.
1          1          2
2          2          3
3          3          4
> df_x <- magical_apply_function(df, function(x) myFun
> df_x
  c.1..2..3. c.2..3..4.
1         myFun(1)         myFun(2)
2         myFun(2)         myFun(3)
3         myFun(3)         myFun(4)

我完全不明白为什么在互联网上找不到这个问题的答案,大多数资源都谈论了 apply, lapply, 和 sapply,但它们只适用于向量/列表,并且它们只返回列表。

难道使用 for 循环是唯一的方法吗?


1
只需使用lapply,请参见下面的@akrun答案。 - Tim Biegeleisen
尽管下面有解决方案,但我不明白为什么你感到困惑。数据框(data.frames)的存在就是为了收集不同的数据。虽然在这里 paste 函数可以起作用,但如果你可以将该函数应用于整个 DF,那么通常它应该是一个矩阵(matrix)。 - Stephen Henderson
奖励:无法处理向量的函数将被应用 - PDiracDelta
4个回答

16
df <- data.frame(c(1,2,3), c(2,3,4))
df[] <- lapply(df, function(x) paste(x,"x", sep=""))
df

df[] 保留了数据框的结构。


当我做类似于这样的事情(相同的原理,不同的函数(X)),我会得到一个错误,指出参数意味着行数不同:3877、 3890、 3884、 3925、 4024、 3942、 2758、 4042、 4796、 7297。我在myFun内部使用了unlist()函数,我认为它正在捣乱长度,因为它正在操作嵌套列表。 - PDiracDelta
哇塞,确实,unlist()函数可以取消多个层次的列表。 - PDiracDelta
1
解决第二个问题的方法是使用unlist()函数,选项为recursive=F,然后一切都能正常工作。 - PDiracDelta

10

我们可以使用来自的mutate_all

library(dplyr)
df %>% 
     mutate_all(funs(paste0(., "x")))

或者使用base Rlapply函数,并将其转换为data.frame

data.frame(lapply(df, paste0,  "x"))

9

您不能使用apply(df, c(1,2), myFun)吗?使用c(1,2)将会逐个在数据框中的每个元素上应用函数:

MARGIN是一个向量,指定了函数所要应用的子脚本。例如对于矩阵而言,1表示行,2表示列,c(1,2)表示行和列。

> temp<-data.frame(le=LETTERS[1:3], nu=20:22)
> temp
  le nu
1  A 20
2  B 21
3  C 22
> apply(temp, c(1,2), function(x) {gsub('d',x,'d1d1')})
     le     nu      
[1,] "A1A1" "201201"
[2,] "B1B1" "211211"
[3,] "C1C1" "221221"

如果你按行应用该函数,则不能正确使用该函数:

> apply(temp, 1, function(x) {gsub('d',x,'d1d1')})
[1] "A1A1" "B1B1" "C1C1"
Warning messages:
1: In gsub("d", x, "d1d1") :
  argument 'replacement' has length > 1 and only the first element will be used
2: In gsub("d", x, "d1d1") :
  argument 'replacement' has length > 1 and only the first element will be used
3: In gsub("d", x, "d1d1") :
  argument 'replacement' has length > 1 and only the first element will be used

花括号可以省略 apply(temp, c(1,2), function(x) gsub('d',x,'d1d1')) - Julien
1
顺便说一下,这个解决方案是该线程中唯一真正回答问题的一个。 - Julien

3

还可以看看这些purrr函数

library(purrr)
modify(df,paste0,"x") # output is of the same type input, so `data.frame` here

#   c.1..2..3. c.2..3..4.
# 1         1x         2x
# 2         2x         3x
# 3         3x         4x

map_df(df,paste0,"x") # output is always tibble

# # A tibble: 3 x 2
#   c.1..2..3. c.2..3..4.
#        <chr>      <chr>
# 1         1x         2x
# 2         2x         3x
# 3         3x         4x

modify 是逐个单元格进行修改吗?我认为它是跨列工作的。 - Julien
1
你说得没错,但问题在回答后被更新了,并且最初使用的是paste函数,而被接受的解决方案也能够正常工作。你评论的apply解决方案并不能真正回答这个问题,因为它返回一个矩阵,但是使用方括号的df[] <- apply(...)可能会奏效。 - moodymudskipper
然而,这个解决方案是目前问题的最佳答案。 - Julien

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接