3

Suppose I have a data frame with a list of names:

> x <- c("a", "b", "c")
> x <- as.data.frame(x)

#  > x
# 1 a
# 2 b
# 3 c

I want to spread each unique name (x, below) to each name (y, below) and create a new column before the original column so that the new data frame looks like this:

#  > z
# x   y
# a   a
# a   b
# a   c
# b   a
# b   b
# b   c
# c   a
# c   b
# c   c 

This is for creating a "from" "to" edge list in igraph where the network is full.

How could I do this? Is there a simple tidyverse solution that I'm missing?

5 Answers5

3

You can use tidyr::expand_grid or tidyr::crossing

tidyr::expand_grid(a = x$x, b = x$x)
#tidyr::crossing(a = x$x, b = x$x)

#  a     b    
#  <chr> <chr>
#1 a     a    
#2 a     b    
#3 a     c    
#4 b     a    
#5 b     b    
#6 b     c    
#7 c     a    
#8 c     b    
#9 c     c    

This is similar to base R expand.grid only the order is different.

expand.grid(a = x$x, b = x$x)
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • Hello dear Ronak Shah, I recently came across a very interesting question on stackoverflow but I couldn't find the solution and it left unaswered. Do you mind if I mention you in a comment and you see if you have any idea how we go about solving it, I would really appreciate it. – Anoushiravan R Mar 27 '21 at 13:35
  • Thank you very much. Here is the link: https://stackoverflow.com/questions/66818393/creating-new-column-based-on-criteria-in-three-other-columns/66832063#66832063 – Anoushiravan R Mar 27 '21 at 13:53
2

Using dplyr and tidyr, you could do:

x %>%
 mutate(y = x) %>%
 complete(y, x)

  y     x    
  <fct> <fct>
1 a     a    
2 a     b    
3 a     c    
4 b     a    
5 b     b    
6 b     c    
7 c     a    
8 c     b    
9 c     c
tmfmnk
  • 38,881
  • 4
  • 47
  • 67
2

A base R solution:

names <- c("a", "b", "c")

x = rep(names, each=length(names))
y = rep(names, length(names))
df = data.frame(x,y)
df
  x y
1 a a
2 a b
3 a c
4 b a
5 b b
6 b c
7 c a
8 c b
9 c c
G5W
  • 36,531
  • 10
  • 47
  • 80
1

You can also use expand function to return every possible combinations of the two columns:

library(tidyr)

x %>%
  mutate(y = x) %>%
  expand(x, y)

# A tibble: 9 x 2
  x     y    
  <chr> <chr>
1 a     a    
2 a     b    
3 a     c    
4 b     a    
5 b     b    
6 b     c    
7 c     a    
8 c     b    
9 c     c 

You can also use crossing function:

x <- c("a", "b", "c")
x <- as.data.frame(x)
x$y <- c("a", "b", "c")

crossing(x$x, x$y)        # But you can't just use it within a pipeline since the first argument is not data

# A tibble: 9 x 2
  `x$x` `x$y`
  <chr> <chr>
1 a     a    
2 a     b    
3 a     c    
4 b     a    
5 b     b    
6 b     c    
7 c     a    
8 c     b    
9 c     c 
Anoushiravan R
  • 21,622
  • 3
  • 18
  • 41
1

If you really want to use igraph, here might be one option

make_full_graph(
  length(x),
  directed = TRUE,
  loops = TRUE
) %>%
  set_vertex_attr(name = "name", value = x) %>%
  get.data.frame()

which gives

  from to
1    a  a
2    a  b
3    a  c
4    b  a
5    b  b
6    b  c
7    c  a
8    c  b
9    c  c
ThomasIsCoding
  • 96,636
  • 9
  • 24
  • 81