stata
stata

Reputation: 533

How to add row percent as new row to dataframe

aaa<-data.frame(group=c("A","B"),x1=c(2,8),x2=c(8,2),total=c(10,10),stringsAsFactors=FALSE)

Now I want to compute row percent as new row below freqency row. New dataframe like:

group   x1      x2     total
 A       2       8       10
 %       20.00   80.00
 B       8       2
 %       80.00   20.00   10

How to do it in R? Thank you!

Upvotes: 2

Views: 558

Answers (1)

Rich Scriven
Rich Scriven

Reputation: 99331

In future questions, please show that you've made at least minimal effort to solve the problem yourself.

Here are two ways that use lapply. The second was added later in an edit because it is much simpler that the first, and probably much faster.

> newD <- do.call(rbind, lapply(seq(nrow(aaa)), function(i){
      x1 <- 100*(aaa$x1[i]/aaa$total[i])
      x2 <- 100*(aaa$x2[i]/aaa$total[i])
      rbind(aaa[i, ], c('%', x1, x2, ''))
  }))
> rownames(newD) <- seq(nrow(newD))
> newD
#    group x1 x2 total
# 1      A  2  8    10
# 2      % 20 80      
# 3      B  8  2    10
# 4      % 80 20

The second, much better lapply method:

> pct <- cbind(group = '%', 100*aaa[2:3]/aaa$total, total = '')
> do.call(rbind, lapply(seq(nrow(aaa)), function(i){ rbind(aaa[i,], pct[i,]) }))
##    group x1 x2 total
## 1      A  2  8    10
## 2      % 20 80      
## 22     B  8  2    10
## 21     % 80 20      

Added, per your comment: A for loop method

> x1 <- x2 <- numeric(nrow(aaa))
> rb <- vector('list', nrow(aaa)/2)

> for(i in seq(nrow(aaa))){
    x1[i] <- 100*(aaa$x1[i]/aaa$total[i])
    x2[i] <- 100*(aaa$x2[i]/aaa$total[i])
    rb[[i]] <- rbind(aaa[i, ], c('%', x1[i], x2[i], ''))
  }

> do.call(rbind, rb)
#    group x1 x2 total
# 1      A  2  8    10
# 2      % 20 80      
# 22     B  8  2    10
# 21     % 80 20      

Upvotes: 3

Related Questions