user11805897
user11805897

Reputation: 11

How to set a loop to assign lots of variables

I just started using R for a psych class, so please go easy on me. I watched a bunch of youtube videos on For loops, but none have answered my question. I have 4 data frames (A, B, C, D), each with 25 columns. I want to combine the nth column from each data frame together, and save them as an object, like so:

Q1 <- cbind(A[1], B[1], C[1], D[1])
Q2 <- cbind(A[2], B[2], C[2], D[2])

How can I set a loop to do this for all 25 so I don’t have to do it manually?

Thanks in advance

Each of my data frames looks like this (with column headings reflecting the letter of the data frame (i.e. B has QB1, QB2, etc.

   QA1 QA2 QA3 QA4 QA5 QA6 QA7 QA8 QA9 QA10 QA11 QA12 QA13 QA14 QA15
1    1   2   2   0   0   2   0   1   0    0    0    0    0    0    0
2    0   0   0   0   0   0   0   0   0    1    0    0    0    1    0
3    1   0   0   0   0   0   1   0   0    2    1    1    0    0    0
4    1   0   0   0   0   0   1   1   0    1    0    2    0    0    0

Upvotes: 1

Views: 179

Answers (2)

Yifu Yan
Yifu Yan

Reputation: 6106

In order to do it in a for loop, you need to use assign() from baseR and eval_tidy(), sym() from rlang(). Basically, you will need to evaluate strings as variables.

Create simulation data


library(rlang)
nrows = 10
ncols = 25
df_names <- c("A","B","C","D")
for(df_name in df_names){
    # assign value to a string as variable
    assign(
        df_name,
        as.data.frame(
            matrix(
                data = sample(
                    c(0,1),
                    size = nrows * ncols,
                    replace = TRUE
                ),
                ncol = 25
            )
        )
    )

    # rename columns
    assign(
        df_name,
        setNames(eval_tidy(sym(df_name)),paste0("Q",df_name,1:ncols))
    )
}

Show A


> head(A)

  QA1 QA2 QA3 QA4 QA5 QA6 QA7 QA8 QA9 QA10 QA11 QA12 QA13 QA14 QA15 QA16 QA17 QA18 QA19 QA20 QA21 QA22 QA23 QA24 QA25
1   1   1   0   0   1   0   1   0   1    1    0    0    1    1    1    0    0    1    0    0    1    1    0    1    1
2   0   1   0   1   1   1   1   0   1    1    1    1    0    0    0    1    0    1    1    0    1    0    1    1    0
3   0   0   0   1   1   0   1   0   1    0    0    1    0    0    0    1    1    1    1    0    0    0    1    1    1
4   0   0   1   1   1   0   0   1   1    1    1    0    1    1    0    1    0    0    0    1    0    1    1    1    1
5   1   1   0   1   1   1   1   1   1    0    1    0    0    0    0    0    1    0    1    0    1    1    0    1    1
6   1   1   0   0   1   1   0   1   1    1    0    1    0    1    1    0    1    0    0    1    1    0    1    1    0

To answer your question:

This should create 25 variables from Q1 to Q25:


# assign dataframes from Q1 to Q25
for(i in 1:25){
    new_df_name <- paste0("Q",i)
    # initialize Qi with the same number of rows as A,B,C,D ...
    assign(
        new_df_name,
        data.frame(tmp = matrix(NA,nrow = rows))
    )
    # loop A,B,C,D ... and bind them
    for(df_name in df_names){
        assign(
            new_df_name,
            cbind(
                eval_tidy(sym(new_df_name)),
                eval_tidy(sym(df_name))[,i,drop = FALSE]
            )
        )
    }
    # drop tmp to clean up
    assign(
        new_df_name,
        eval_tidy(sym(new_df_name))[,-1]
    )
}

Show result:

> Q25
   QA25 QB25 QC25 QD25
1     1    0    1    1
2     0    1    0    0
3     1    1    0    0
4     1    0    1    1
5     1    1    0    0
6     0    1    1    1
7     1    0    0    0
8     0    0    0    1
9     1    1    1    0
10    0    0    1    1

The codes should be much easier if you save results in a list using map(). The major complexity is from assigning values to separate variables.

Upvotes: 3

kstew
kstew

Reputation: 1114

You can combine some dplyr verbs in a for loop to combine the columns from each data set and assign them to 25 new objects.

# merge data, gather, split by var numbers, assign each df to environment
for (i in 1:25) {
  df <- cbind(q1,q2,q3,q4) %>% mutate(id=row_number()) %>% 
    gather(k,v,-id) %>% 
    mutate(num=sub('A|B|C|D','',k)) %>% 
    filter(num==i) %>% select(-num) %>% spread(k,v)
  assign(paste0('df',i),df)
}

ls(pattern = 'df')

 [1] "df1"  "df10" "df11" "df12" "df13" "df14" "df15" "df16" "df17" "df18" "df19" "df2" 
[13] "df20" "df21" "df22" "df23" "df24" "df25" "df3"  "df4"  "df5"  "df6"  "df7"  "df8" 
[25] "df9" 

Code to create initial 4 toy data frames.

# create four toy data frames
q1 <- data.frame(matrix(runif(100),ncol=25))
q2 <- data.frame(matrix(runif(100),ncol=25))
q3 <- data.frame(matrix(runif(100),ncol=25))
q4 <- data.frame(matrix(runif(100),ncol=25))

# set var names for each toy data
names(q1) <- sub('X','A',names(q1))
names(q2) <- sub('X','B',names(q2))
names(q3) <- sub('X','C',names(q3))
names(q4) <- sub('X','D',names(q4))

Upvotes: 0

Related Questions