用于在 R 中创建和求和子集的用户定义函数

Posted

技术标签:

【中文标题】用于在 R 中创建和求和子集的用户定义函数【英文标题】:User Defined Function to create and sum a subset in R 【发布时间】:2017-11-17 23:15:46 【问题描述】:

我需要帮助定义一个在数据库中创建向量的函数,对于每一行,该函数查看该数据库中的另一列,在单独数据库的指定列中搜索该值,创建该向量的子集由所有匹配行组成的第二个数据库,对该新子集的单独列求和,并将该值返回到原始数据库中新列的相应行。

换句话说,我有一个看起来像这样的数据框:

ID <- c('a', 'b', 'c', 'd', 'e')
M <- 20:39
df <- data.frame(cbind(ID, M))
df$M <- as.numeric(df$M)
> df
   ID  M
1   a  1
2   b  2
3   c  3
4   d  4
5   e  5
6   a  6
7   b  7
8   c  8
9   d  9
10  e 10
11  a 11
12  b 12
13  c 13
14  d 14
15  e 15
16  a 16
17  b 17
18  c 18
19  d 19
20  e 20
> str(df)
'data.frame':   20 obs. of  2 variables:
 $ ID: Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5 1 2 3 4 5 ...
 $ M : num  1 2 3 4 5 6 7 8 9 10 ...

我想创建一个新的数据框Z,这样Z &lt;- data.frame(cbind(X, Y)) 其中:

X <- as.character(unique(df$ID))
> X
[1] "a" "b" "c" "d" "e"

Y 是所有 a 的总和、所有 b 的总和、所有 c 的总和等的向量......

所以,Y 应该等于 c(34, 38, 42, 46, 50),我的最终结果应该是:

> Z
  X  Y
1 a 34
2 b 38
3 c 42
4 d 46
5 e 50
> str(Z)
'data.frame':   5 obs. of  2 variables:
 $ X: chr  "a" "b" "c" "d" ...
 $ Y: num  34 38 42 46 50

为此,我首先尝试将X 转换为数据框(作为数据表更容易使用吗?):

> Z <- data.frame(X)
> Z
  X
1 a
2 b
3 c
4 d
5 e
> str(Z)
'data.frame':   5 obs. of  1 variable:
 $ X: Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5

然后将 Y 定义为 Z$Y &lt;- sum(df[df$ID == Z$X, 2]) 但我没有得到唯一值:

> Z
  X   Y
1 a 210
2 b 210
3 c 210
4 d 210
5 e 210

我也尝试过像这样定义函数f1()

f1 <- function(v, w, x, y, z)sum(v[v$w == x$y, z])

但这让我明白了:

> f1(df, 'ID', Z, 'X', 'M')
[1] 0

我在这个论坛的另一篇帖子中发现了一个功能类似的功能:

f1 <- function(df, cols, match_with, to_x = 50)
  df[cols] <- lapply(df[cols], function(i) 
    ifelse(grepl(to_x, match_with, fixed = TRUE), 'MID', 
           i))
  return(df)

这会在match_with 列中查找值“50”,并将值“MID”返回到cols 指定的列的那一行,前提是两列都在同一个指定数据库df 中。因此,我需要将to_x = 50 替换为某种东西,而不是寻找固定值“50”,而是寻找列Z$X 中的任何值,而不是返回固定值“MID”,而是返回df[df$ID == Z$X, df$M] 的值的总和。我自己通过编写以下变体尝试了这些更改:

f1 <- function(df, cols, match_with, to_x = df[ , 1], x)
  df[cols] <- lapply(df[cols], function(i) 
    ifelse(grepl(to_x, match_with, fixed = TRUE), sum(x), 
           i))
  return(df)

但是,到目前为止,我的所有变体都没有产生预期的结果。这个给了我:

> f1(Z, df, cols = c('Y'), match_with = df$ID, x = df$M)
  X   Y
1 a 210
2 b 210
3 c 210
4 d 210
5 e 210
Warning messages:
1: In grepl(to_x, match_with, fixed = TRUE) :
  argument 'pattern' has length > 1 and only the first element will be used
2: In `[<-.data.frame`(`*tmp*`, cols, value = list(Y = c(210, 210,  :
  replacement element 1 has 20 rows to replace 5 rows

它似乎是对整个 df$M 求和,而不是对 df$ID == Z$X 的子集求和。在其他变体中,它似乎在引用第二个数据框中的列时遇到问题。

我对 R 有点陌生,几乎没有编写用户定义函数的经验(正如您可能从这个问题中看出的那样)。任何帮助将不胜感激!

【问题讨论】:

【参考方案1】:

没关系,我想我明白了!

> f1 <- function(col1, col2, df2, to_add)
+ lapply(col1, function(i)
+   df2$x <- grepl(i, col2, fixed = TRUE)
+   df3 <- df2[df2$x == TRUE, to_add]
+   sum(df3, na.rm = TRUE)
+ )
> Z$Y <- f1(Z$X, df$ID, df, c('M'))
> Z
  X  Y
1 a 34
2 b 38
3 c 42
4 d 46
5 e 50

【讨论】:

以上是关于用于在 R 中创建和求和子集的用户定义函数的主要内容,如果未能解决你的问题,请参考以下文章

在 R 中的函数中创建和使用新变量:tidyverse 中的 NSE 编程错误

在C ++中创建和使用动态数组

如何在整个应用程序中创建和注入用户特定的单例类?

Parse用户在应用程序中创建和加入组

在java中创建和初始化对象

如何在 Protractor 中创建和操作 Promise?