Вычисление вхождений чисел в подмножествах data.frame

У меня есть кадр данных в 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) и для каждой группы идентификаторов (1,2,3) (для этой последней группы см. мой столбец 'id ').

Итак, для столбца «a» и для идентификатора «1» (для последнего см. столбец «id») код будет примерно таким:

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

##The results are:
[1] 3 7

Кратко поясню мои результаты: в столбце «a» (и в отношении только тех записей, у которых в столбце «id» есть число «1») мы можем сказать, что число «1» встречается 3 раза, а число «3» встречается 7 раз.

Опять же, просто чтобы показать вам еще один пример. Для столбца «a» и для идентификатора «2» (для последней группы см. снова столбец «id»):

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

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

Позвольте мне еще раз немного объяснить: в столбце «а» и только в отношении тех наблюдений, которые имеют номер «2» в столбце «id»), мы можем сказать, что число «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 и т. д. Но сейчас я действительно застрял и не знаю, как двигаться дальше…

Есть ли правильный, «автоматический» способ решить эту проблему?


person Laszlo    schedule 17.03.2011    source источник


Ответы (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

Итак, чтобы получить количество «3» в столбце «а» и группе «1», вы можете просто сделать

> dftab[3,'a',1]
[1] 4
person wkmor1    schedule 17.03.2011

Комбинация tapply и apply может создать нужные вам данные:

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
person James    schedule 17.03.2011
comment
Вы можете использовать множитель, чтобы убедиться, что нулевые счетчики проходят: lapply(split(df[-1], df$id), apply, 2, function(x) table(factor(x, 1:3))) - person Charles; 17.03.2011

Я уверен, что у кого-то будет более элегантное решение, чем это, но вы можете собрать его вместе с простой функцией и dlply из пакета plyr.

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; во-вторых, результаты table для каждого столбца для этой переменной id. Например:

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

1 2 3 
4 3 3 

Для переменной id = 2, столбец = a, согласно приведенному выше примеру.

person Noah    schedule 17.03.2011

Способ сделать это - использовать функцию 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
person arinarmo    schedule 31.03.2014

Вы не сказали, как вам нужны данные. Функция by может дать вам желаемый результат.

by(df, df$id, function(x) lapply(x[,-1], table))
person John    schedule 26.05.2014