Home > Back-end >  Splitting data.frame into matrices and multiplying the diagonal elements to produce a new column
Splitting data.frame into matrices and multiplying the diagonal elements to produce a new column

Time:09-26

here is my data structure ;

structure(list(a = c(57L, 39L, 31L, 70L, 8L, 93L, 68L, 85L), 
    b = c(161L, 122L, 101L, 104L, 173L, 192L, 110L, 152L)), class = "data.frame", row.names = c(NA, 
-8L))

each two row represents a separate matrix, for example;

      a     b
  <int> <int>
1    57   161
2    39   122

I want to multiply first row's a and second row's b then save it into a variable called c. Then repeat the operation for first row's b and second row's a then save it c again.

For a matrix, desired output is like this;

      a     b     c
  <int> <int> <dbl>
1    57   161  6954
2    39   122  6279

For whole data, desired output is like this;

      a     b     c
  <int> <int> <dbl>
1    57   161  6954
2    39   122  6279
3    31   101  3224
4    70   104  7070
5     8   173  1536
6    93   192 16089
7    68   110 10336
8    85   152  9350

base R functions would be much better.

Thanks in advance.

CodePudding user response:

We can create a group with gl

library(dplyr)
df1 %>% 
   group_by(grp = as.integer(gl(n(), 2, n()))) %>% 
   mutate(c = a * rev(b)) %>%
   ungroup %>% 
   select(-grp)

-output

# A tibble: 8 × 3
      a     b     c
  <int> <int> <int>
1    57   161  6954
2    39   122  6279
3    31   101  3224
4    70   104  7070
5     8   173  1536
6    93   192 16089
7    68   110 10336
8    85   152  9350

Or with ave from base R

df1$c <- with(df1, a * ave(b, as.integer(gl(length(b), 2, length(b))), FUN = rev))
df1$c
[1]  6954  6279  3224  7070  1536 16089 10336  9350

CodePudding user response:

Here's another way -

inds <- seq(nrow(df))
df$c <- df$a * df$b[inds   rep(c(1, -1), length.out = nrow(df))]
df

#   a   b     c
#1 57 161  6954
#2 39 122  6279
#3 31 101  3224
#4 70 104  7070
#5  8 173  1536
#6 93 192 16089
#7 68 110 10336
#8 85 152  9350

Explanation -

We create an alternating 1 and -1 value and add it to the row number generate to get the corresponding b value to multiply with a.

inds
#[1] 1 2 3 4 5 6 7 8

rep(c(1, -1), length.out = nrow(df))
#[1]  1 -1  1 -1  1 -1  1 -1

inds   rep(c(1, -1), length.out = nrow(df))
#[1] 2 1 4 3 6 5 8 7
  • Related