在数据框的子集中计算数字出现的次数

3

我在R中有一个数据框,类似于以下内容。实际上,我的真实“df”数据框比这个要大得多,但我真的不想让任何人感到困惑,所以我尽可能地简化了事情。

这就是数据框:

id <-c(1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3)   
a <-c(3,1,3,3,1,3,3,3,3,1,3,2,1,2,1,3,3,2,1,1,1,3,1,3,3,3,2,1,1,3)
b <-c(3,2,1,1,1,1,1,1,1,1,1,2,1,3,2,1,1,1,2,1,3,1,2,2,1,3,3,2,3,2)
c <-c(1,3,2,3,2,1,2,3,3,2,2,3,1,2,3,3,3,1,1,2,3,3,1,2,2,3,2,2,3,2)
d <-c(3,3,3,1,3,2,2,1,2,3,2,2,2,1,3,1,2,2,3,2,3,2,3,2,1,1,1,1,1,2)
e <-c(2,3,1,2,1,2,3,3,1,1,2,1,1,3,3,2,1,1,3,3,2,2,3,3,3,2,3,2,1,3)

df <-data.frame(id,a,b,c,d,e)
df

我想做的基本上是获取每个列(a,b,c,d,e)和每个id组(1、2、3)中数字出现的次数(对于后者分组,请参见我的“id”列)。

因此,对于列'a'和id编号'1'(对于后者请参见列'id'),代码将如下所示:

as.numeric(table(df[1:10,2]))

##The results are:
[1] 3 7

简单说明一下我的结果:在列'a'中(仅考虑列'id'中数字为'1'的记录),我们可以看到数字'1'出现了3次,数字'3'出现了7次。

再举一个例子。对于列'a'和id号码'2'(对于后面的分组请再次查看列'id'):

as.numeric(table(df[11:20,2]))

##After running the codes the results are: 
[1] 4 3 3

让我再解释一下:在列'a'中,只考虑那些在'id'列中有数字'2'的观测值,我们可以说数字'1'出现了4次,数字'2'出现了3次,数字'3'出现了3次。
所以这就是我想做的事情。计算每个自定义子集中数字的出现次数(然后将这些值收集到数据框中)。我知道这不是一个困难的任务,但问题在于我需要经常改变输入的'df'数据框,因此随着时间的推移,行和列的总数可能会发生变化...
到目前为止,我已经按列分离了'df'数据框,像这样:
for (z in (2:ncol(df))) assign(paste("df",z,sep="."),df[,z])

所以,df.2将引用df$a,df.3将等于df$b,df.4将等于df$c等。但是我现在真的卡住了,不知道该如何继续...

有没有适当的“自动”解决此问题的方法?

5个回答

5

你能否翻译 -

> library(reshape)

> dftab <- table(melt(df,'id'))
> dftab
, , value = 1

   variable
id  a b c d e
  1 3 8 2 2 4
  2 4 6 3 2 4
  3 4 2 1 5 1

, , value = 2

   variable
id  a b c d e
  1 0 1 4 3 3
  2 3 3 3 6 2
  3 1 4 5 3 4

, , value = 3

   variable
id  a b c d e
  1 7 1 4 5 3
  2 3 1 4 2 4
  3 5 4 4 2 5

如果你想要在列 'a' 和分组 '1' 中计算出数字 '3' 的数量,你可以直接执行以下操作:

> dftab[3,'a',1]
[1] 4

2

结合使用tapplyapply可以创建您想要的数据:

tapply(df$id,df$id,function(x) apply(df[id==x,-1],2,table))

然而,当一个组中没有所有的元素,如1a,结果将是该id组的列表,而不是漂亮的表格(矩阵)。
$`1`
$`1`$a

1 3 
3 7 

$`1`$b

1 2 3 
8 1 1 

$`1`$c

1 2 3 
2 4 4 

$`1`$d

1 2 3 
2 3 5 

$`1`$e

1 2 3 
4 3 3 


$`2`
  a b c d e
1 4 6 3 2 4
2 3 3 3 6 2
3 3 1 4 2 4

$`3`
  a b c d e
1 4 2 1 5 1
2 1 4 5 3 4
3 5 4 4 2 5

您可以使用一个因子来确保零计数被传递:lapply(split(df[-1], df$id), apply, 2, function(x) table(factor(x, 1:3))) - Charles

0
我相信肯定有比这更优雅的解决方案,但是你可以用一个简单的函数和 plyr 包中的 dlply 函数拼凑起来。
ColTables <- function(df) {
  counts <- list()
  for(a in names(df)[names(df) != "id"]) {
    counts[[a]] <- table(df[a])
  }
  return(counts)
}

results <- dlply(df, "id", ColTables)

这将返回一个列表 - 列表的第一层将是id变量; 第二层是该id变量每个列的table结果。例如:

> results[['2']]['a']
$a

1 2 3 
4 3 3 

根据您上面的示例,对于id变量=2,列=a。


0
你没有说你想要数据的形式。使用 by 函数可能会给你想要的输出。
by(df, df$id, function(x) lapply(x[,-1], table))

0
一种方法是使用aggregate函数,但您需要向数据框添加一列。
> df$freq <- 0
> aggregate(freq~a+id,df,length)
  a id freq
1 1  1    3
2 3  1    7
3 1  2    4
4 2  2    3
5 3  2    3
6 1  3    4
7 2  3    1
8 3  3    5

当然,你可以编写一个函数来完成它,这样就更容易频繁地进行操作,而且不必向实际数据框添加列。
> frequency <- function(df,groups) {
+   relevant <- df[,groups]
+   relevant$freq <- 0
+   aggregate(freq~.,relevant,length)
+ }
> frequency(df,c("b","id"))
  b id freq
1 1  1    8
2 2  1    1
3 3  1    1
4 1  2    6
5 2  2    3
6 3  2    1
7 1  3    2
8 2  3    4
9 3  3    4

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