2
\$\begingroup\$

tibbles documentation

I've got this doing what I want, but it's using a for loop and I've read many times to avoid for loops in R for efficiency and style. Well, it's not a computationally demanding task and I think it might be as clear as it could be in a for loop. In any case, it seems a bit tricky to process this functionally rather than iteratively.

I'm starting with one tibble: source_tbl.
I want to make another tibble: constructed_tbl.
Every column in constructed_tbl is a sum of a subset of columns in source_tbl.

The column mapping is stored in col_conversion_tbl.

>print(col_conversion_tbl)

# A tibble: 6 x 2
source_col       constructed_col
<chr>            <chr>
1 col1             A
2 col2             A
3 col3             A
4 col4             A
5 col5             B
6 col6             B

So,
constructed_tbl[,'A']

should be equal to ...

rowSums(source_tbl[,c('col1','col2','col3','col4')])

The best way I've come up with

The best way I've come up with is to

  • convert col_conversion_tbl to a list, col_conversion_lst, where each item is an array of source_cols and is named after a constructed_col.
  • initialize an empty constructed_tbl tibble w/ appropriate nrows, ncols, and column names
  • Loop through names(col_conversion_lst) replacing the empty column from constructed_tbl with the sum of the appropriate columns from source_tbl.

Here's my code

library(tibble)
library(magrittr)
library(purrr)

source_tbl <- tibble(col1=c(1,1,1),col2=c(2,2,2),col3=c(3,3,3),col4=c(4,4,4),col5=c(5,5,5),col6=c(6,6,6))
col_conversion_tbl <- tibble(source_col = c('col1','col2','col3','col4','col5','col6'), constructed_col = c('A','A','A','A','B','B'))

col_conversion_lst <- col_conversion_tbl %>% 
    split(.$constructed_col) %>% 
    map(~.$source_col)

constructed_tbl <- as_tibble(matrix(nrow=nrow(source_tbl),ncol= length(col_conversion_lst) ))
colnames(constructed_tbl) <- names(col_conversion_lst)  

for (n in names(col_conversion_lst)){
    constructed_tbl[,n] <- rowSums(source_tbl[ ,col_conversion_lst[[n]]])
}
\$\endgroup\$
  • \$\begingroup\$ Welcome to Code Review. You might want to include a reference about what a tibble is. \$\endgroup\$ – Simon Forsberg Mar 16 '18 at 19:37
  • \$\begingroup\$ Thank you. I added a link, but shouldn't I expect that anyone who could answer this question would already know what a tibble is? \$\endgroup\$ – timwiz Mar 16 '18 at 19:40
  • \$\begingroup\$ Sure, but don't expect the readers of your question to know what a tibble is. The more readers can understand of your code the easier it is to post an answer. I'd recommend taking a look at Simon's Guide to posting a good question. In particular, you could improve {todo}. \$\endgroup\$ – Simon Forsberg Mar 16 '18 at 21:11
4
\$\begingroup\$

I would use a matrix multiplication. It is both efficient and leads to much shorter code, as you can see:

constructed_tbl <- as.tibble(as.matrix(source_tbl) %*% table(col_conversion_tbl))
\$\endgroup\$
  • \$\begingroup\$ This is a great answer. In reality, my source_tbl contains many more columns than just those listed in the col_conversion_tbl. So in order to use this method I just need to add a line that selects only those columns in source_tbl that are found in source_col from col_conversion_tbl: source_tbl <- source_tbl %>% select(col_conversion_tbl$source_col) \$\endgroup\$ – timwiz Apr 12 '18 at 13:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.