title: Correlations between numerous variables grouped in dplyr
body: <p>Say I have a data frame, like this:</p>
  <pre><code># Set RNG seed
  set.seed(33550336)
  
  # Create dummy data frame
  df &lt;- data.frame(PC1 = runif(20),
                   PC2 = runif(20),
                   PC3 = runif(20),
                   A = runif(20),
                   B = runif(20),
                   loc = sample(LETTERS[1:2], 20, replace = TRUE),
                   seas = sample(c(&quot;W&quot;, &quot;S&quot;), 20, replace = TRUE))
  
  # &gt; head(df)
  #         PC1        PC2       PC3         A         B loc seas
  # 1 0.8636470 0.02220823 0.7553348 0.4679607 0.0787467   A    S
  # 2 0.3522257 0.42733152 0.2412971 0.6691419 0.1194121   A    W
  # 3 0.5257408 0.44293320 0.3225228 0.0934192 0.2966507   B    S
  # 4 0.0667227 0.90273594 0.6297959 0.1962124 0.4894373   A    W
  # 5 0.3751383 0.50477920 0.6567203 0.4510632 0.4742191   B    S
  # 6 0.9197086 0.32024904 0.8382138 0.9907894 0.9335657   A    S
  </code></pre>
  <p>I'm interested in calculating correlations between <code>PC1</code>, <code>PC2</code>, and <code>PC3</code> and each of the variables <code>A</code> and <code>B</code> grouped by <code>loc</code> and <code>seas</code>. So, for example, based on <a href="https://stackoverflow.com/a/51731607/1552004">this answer</a>, I could do the following:</p>
  <pre><code># Correlation of variable A and PC1 per loc &amp; seas combination
  df %&gt;% 
    group_by(loc, seas) %&gt;% 
    summarise(cor = cor(PC1, A)) %&gt;% 
    ungroup
  
  # # A tibble: 4 x 3
  #   loc   seas      cor
  #   &lt;fct&gt; &lt;fct&gt;   &lt;dbl&gt;
  # 1 A     S      0.458 
  # 2 A     W      0.748 
  # 3 B     S     -0.0178
  # 4 B     W     -0.450 
  </code></pre>
  <p>This gives me what I want: the correlation between <code>PC1</code> and <code>A</code> for each combination of <code>loc</code> and <code>seas</code>. <em>Awesome</em>.</p>
  <p>What I'm struggling with is extrapolating this to perform the calculation for each combination of <code>PC*</code> variables and other variables (i.e., <code>A</code> and <code>B</code>, in the example). My expected outcome is the tibble immediately above, but with a column for each combination for <code>PC*</code> and the other variables. I could do this long hand... <code>cor(PC2, A)</code>, <code>cor(PC3, A)</code>, <code>cor(PC1, B)</code>, etc., but presumably there is there a succinct way of coding the calculation. I suspect it involves <code>do</code>, but I can't quite get my head around it... Can someone enlighten me?</p>
  <hr />
  <h2>Solution</h2>
  <p>I went with G. Grothendieck's <a href="https://stackoverflow.com/a/53764977/1552004">solution below</a>, but this required some restructuring to get it into the required format. I have posted the code I used here in case it is useful for others.</p>
  <pre><code># Perform calculation
  res &lt;- by(df[1:5], df[-(1:5)], cor)
  
  # Combinations of loc &amp; seas 
  comb &lt;- expand.grid(dimnames(res))
  
  #   loc seas
  # 1   A    S
  # 2   B    S
  # 3   A    W
  # 4   B    W
  
  # A matrix corresponding to a loc &amp; seas
  # Plus the loc &amp; seas themselves
  restructure &lt;- function(m, n){
    # Convert to data frame
    # Add rownames as column
    # Retains PCs as rows, but not columns
    # Gather variables to long format
    # Unite PC &amp; variable names
    # Spread to a single row
    # Add combination of loc &amp; seas
    m %&gt;% 
      data.frame %&gt;% 
      rownames_to_column() %&gt;% 
      filter(grepl(&quot;PC&quot;, rownames(m))) %&gt;% 
      select(-contains(&quot;PC&quot;)) %&gt;% 
      gather(variable, value, -rowname) %&gt;% 
      unite(comb, rowname, variable) %&gt;% 
      spread(comb, value) %&gt;% 
      bind_cols(n)
  }
  
  # Restructure each list element &amp; combine into data frame
  do.call(rbind, lapply(1:length(res), function(x)restructure(res[[x]], comb[x, ])))
  </code></pre>
  <p>which gives,</p>
  <pre><code>#         PC1_A       PC1_B      PC2_A       PC2_B      PC3_A     PC3_B loc seas
  # 1  0.45763159 -0.00925106  0.3522161  0.20916667 -0.2003091 0.3741403   A    S
  # 2 -0.01779813 -0.74328144 -0.3501188  0.46324158  0.8034240 0.4580262   B    S
  # 3  0.74835455  0.49639477 -0.3994917 -0.05233889 -0.5902400 0.3606690   A    W
  # 4 -0.45025181 -0.66721038 -0.9899521 -0.80989058  0.7606430 0.3738706   B    W
  </code></pre>