简体   繁体   English

如何使用R将分类数据转换为相对计数

[英]How to turn categorical data into relative counts with R

Minimal example 最小的例子

I have: input<-data.frame(id=c(1,1,1,2,2,2),A=as.factor(c(1,1,2,2,1,3)),B=as.factor(c(0,1,1,1,0,0))) 我有: input<-data.frame(id=c(1,1,1,2,2,2),A=as.factor(c(1,1,2,2,1,3)),B=as.factor(c(0,1,1,1,0,0)))

I want: output<-data.frame(id=c(1,2), A1=c(2/3,1/3), A2=c(1/3,1/3), A3=c(0/3,1/3), B0=c(1/3,2/3), B1=c(2/3,1/3)) 我想: output<-data.frame(id=c(1,2), A1=c(2/3,1/3), A2=c(1/3,1/3), A3=c(0/3,1/3), B0=c(1/3,2/3), B1=c(2/3,1/3))

Motivation 动机

I have a data frame with categorical data. 我有一个带有分类数据的数据框。 I would like to turn this into a dataframe with proportianal counts of each category occuring. 我想把它变成一个数据框,其中包含每个类别的比例计数。 In the "output" dataframe I would like to have a column for each variable-category combination (A1,A2, etc.). 在“输出”数据框中,我希望每个变量类别组合(A1,A2等)都有一列。 Each row gives the relative counts for a "id". 每行给出“id”的相对计数。 For instance, id=1 has three entries in "input" with two times category 1 under variable "A". 例如,id = 1在“input”中有三个条目,在变量“A”下有两次类别1。 The column "A1" should show 2/3 in that row. 列“A1”应该在该行中显示2/3。 Divided by three, because id=1 has three entries in "input". 除以3,因为id = 1在“input”中有三个条目。

What I started 我开始的

function(input){

#create empty dataframe
distcID<-duplicated(input$id)
output<-data.frame(id=integer(0),A1=integer(0),A2=integer(0),A3=integer(0),
                 B0=integer(0),B1=integer(0))

count<-0

for (i in input$id[distcID]){
df.cID<-input[input$customer_ID==i]
m<- NROW(df.cID)
count<-count+1
output$customer_ID[count]<-i
output$A1[count]<-1/m*NROW(df.cID$A==1)
output$A2[count]<-1/m*NROW(df.cID$A==2)
output$A3[count]<-1/m*NROW(df.cID$A==3)
output$B0[count]<-1/m*NROW(df.cID$B==0)
output$B1[count]<-1/m*NROW(df.cID$B==1)
}
return(output)

}

What is wrong? 怎么了? - it is ugly. - 它太丑了。 Given functions like apply and aggregate or a package like plyr, there should be nicer (ie shorter) solutions to this problem. 给定像apply和aggregate这样的函数或像plyr这样的包,应该有更好(即更短)的解决方案来解决这个问题。

  • R does not accept the initialization of output with empty columns. R不接受空列的输出初始化。

  • the column names of output are not created automatically, but by hand. 输出的列名不是自动创建的,而是手动创建的。

Thank you! 谢谢! Please tell me if my question lacks clarity. 如果我的问题不明确,请告诉我。 This is my first question here. 这是我的第一个问题。

This expression creates a table for each of the non-ID columns (here, 2:3 ): 此表达式为每个非ID列创建一个表(此处为2:3 ):

individuals <- lapply(2:3, function(i) {
  # Table of counts, by "id"
  x <- table(input[,c(1,i)])

  # Scale to proportions
  x <- x / rowSums(x)

  # Fix the names
  colnames(x) <- paste0(colnames(input)[i], colnames(x))

  return(x)
}
)

individuals
## [[1]]
##    A
## id         A1        A2        A3
##   1 0.6666667 0.3333333 0.0000000
##   2 0.3333333 0.3333333 0.3333333
## 
## [[2]]
##    B
## id         B0        B1
##   1 0.3333333 0.6666667
##   2 0.6666667 0.3333333

Now put them together with cbind : 现在将它们与cbind放在一起:

do.call(cbind, individuals)
##          A1        A2        A3        B0        B1
## 1 0.6666667 0.3333333 0.0000000 0.3333333 0.6666667
## 2 0.3333333 0.3333333 0.3333333 0.6666667 0.3333333

The id column is not present, but the row names can be used for this purpose. id列不存在,但行名称可用于此目的。

This isn't a complete answer, but should help you along the way (with a bit of resphape[2] -ing: 这不是一个完整的答案,但应该帮助你一路走来(有点resphape[2] -ing:

ct <- count(input, "id")
A <- data.frame(table(input[,c(1,2)])/ct[ct$id==1,]$freq)
B <- data.frame(table(input[,c(1,3)])/ct[ct$id==2,]$freq)

print(A)
  id A      Freq
1  1 1 0.6666667
2  2 1 0.3333333
3  1 2 0.3333333
4  2 2 0.3333333
5  1 3 0.0000000
6  2 3 0.3333333

print(B)
  id B      Freq
1  1 0 0.3333333
2  2 0 0.6666667
3  1 1 0.6666667
4  2 1 0.3333333

Here's on possible solution: 这是可能的解决方案:

library(reshape2)
library(qdap)

x <- prop.table(ftable(melt(input, id="id")))
x2 <- colpaste2df(data.frame(x), 2:3, keep.orig = FALSE, sep="", name.sep = "")
x3 <- dcast(x2, id  ~ variablevalue, value.var = "Freq")
x3[, c(TRUE, colSums(x3[, -1]) != 0)]

##   id         A1         A2         A3         B0         B1
## 1  1 0.16666667 0.08333333 0.00000000 0.08333333 0.16666667
## 2  2 0.08333333 0.08333333 0.08333333 0.16666667 0.08333333

Can be seen as a pivot table (or two pivot tables): 可以看作是一个数据透视表(或两个数据透视表):

>install.packages('reshape')
>library(reshape)
>ct <-count(input, "id")
>DF1<-cast(input, id ~ A, value='B')
>DF2<-cast(input, id ~ B, value="A")
>DF3<-cbind(DF1$id, DF1[names(DF1)!='id']/ct[1,]$freq, DF2[names(DF2)!='id']/ct[2,]$freq)
>names(DF3)<-c('id', paste('A', names(DF1)[-1], sep=''), paste('B', names(DF2)[-1], sep=''))
> DF3
  id        A1        A2        A3        B0        B1
1  1 0.6666667 0.3333333 0.0000000 0.3333333 0.6666667
2  2 0.3333333 0.3333333 0.3333333 0.6666667 0.3333333

This is what I think you wanted. 这就是我想你想要的。 Just add row or column names to suit your tastes. 只需添加行名或列名即可满足您的口味。

 tbB <- with(input, table(B, id))
 tbA <- with(input, table(A, id))
 cbind( t( tbA/rowSums(tbA)), t(tbB/rowSums(tbB)) )
          1   2 3         0         1
1 0.6666667 0.5 0 0.3333333 0.6666667
2 0.3333333 0.5 1 0.6666667 0.3333333

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM