0

lets say I have a list of dataframes different numbers of rows:

AB_df = data.frame(replicate(2,sample(0:130,201,rep=TRUE)))
BC_df = data.frame(replicate(2,sample(0:130,200,rep=TRUE)))
DE_df = data.frame(replicate(2,sample(0:130,197,rep=TRUE)))
FG_df = data.frame(replicate(2,sample(0:130,203,rep=TRUE)))

AB_pc = data.frame(replicate(2,sample(0:130,201,rep=TRUE)))
BC_pc = data.frame(replicate(2,sample(0:130,200,rep=TRUE)))
DE_pc = data.frame(replicate(2,sample(0:130,197,rep=TRUE)))
FG_pc = data.frame(replicate(2,sample(0:130,203,rep=TRUE)))

df_list = list(AB_df, BC_df, DE_df, FG_df, AB_pc, BC_pc, DE_pc, FG_pc)
names(df_list) = c("AB_df", "BC_df", "DE_df", "FG_df", "AB_pc", "BC_pc", "DE_pc", "FG_pc")

I want to split the nested dataframes into n equal, but random pieces so that I have e.g. for 4 pieces 4 dataframes with 50 rows and 1 with 51 rows. No row should be twice in any od the splitted dataframes.

The structure should be:

List of 8
 $ AB_df: list of 4
      $ AB_df1: "data.frame": 50 obs. of 2 variables
          ..$ X1: int [1:50] 88 128....
          ..$ X2: int [1:50] 12 84 ....
      $ AB_df2: "data.frame": 50 obs. of 2 variables
          ..$ X1: int [1:50] numbers...
          ..$ X2: int [1:50] numbers....
      $ AB_df3: "data.frame": 50 obs. of 2 variables
          ..$ X1: int [1:50] numbers...
          ..$ X2: int [1:50] numbers....
      $ AB_df4: "data.frame": 51 obs. of 2 variables
          ..$ X1: int [1:50] numbers...
          ..$ X2: int [1:50] numbers....
 $ BC_df:'list of 4
      $ BC_df1: "data.frame": 50 obs. of 2 variables
          ..$ X1: int [1:50] numbers...
          ..$ X2: int [1:50] numbers....
      $ BC_df2: "data.frame": 50 obs. of 2 variables
          ..$ X1: int [1:50] numbers...
          ..$ X2: int [1:50] numbers....
 ............................

I found several topics on how to split a dataframe randomly, but non of these topics helped me with my problem.

UPDATE: This only gives me 3 splitted dataframes for some reason.

set.seed(0L)
AB_df = data.frame(replicate(2,sample(0:130,1624,rep=TRUE)))
BC_df = data.frame(replicate(2,sample(0:130,1656,rep=TRUE)))
DE_df = data.frame(replicate(2,sample(0:130,1656,rep=TRUE)))
FG_df = data.frame(replicate(2,sample(0:130,1729,rep=TRUE)))

AB_pc = data.frame(replicate(2,sample(0:130,1624,rep=TRUE)))
BC_pc = data.frame(replicate(2,sample(0:130,1656,rep=TRUE)))
DE_pc = data.frame(replicate(2,sample(0:130,1656,rep=TRUE)))
FG_pc = data.frame(replicate(2,sample(0:130,1729,rep=TRUE)))

df_list = list(AB_df, BC_df, DE_df, FG_df, AB_pc, BC_pc, DE_pc, FG_pc)
names(df_list) = c("AB_df", "BC_df", "DE_df", "FG_df", "AB_pc", "BC_pc", "DE_pc", "FG_pc")

new = lapply(df_list, function(df) {
  n <- nrow(df)
  split(df, cut(sample(n), seq(1, n, by=floor(n/4)), labels=FALSE, include.lowest=TRUE))})
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
Mr.Spock
  • 511
  • 2
  • 13
  • Not about the actual question, but FYI `purrr::lst` does what you've got in your `list` and `names(df_list)` lines – camille Oct 08 '19 at 14:32

1 Answers1

3

You can use cut with split to do this:

k <- 4
str(
    lapply(df_list, function(df) {
        n <- nrow(df)
        split(df, cut(sample(n), seq(0, (k+1)*ceiling(n/k), by=ceiling(n/k)), labels=FALSE))
    })
)

output:

List of 8
 $ AB_df:List of 4
  ..$ 1:'data.frame':   51 obs. of  2 variables:
  .. ..$ X1: int [1:51] 13 50 84 6 109 125 88 120 38 41 ...
  .. ..$ X2: int [1:51] 36 107 14 71 92 115 130 126 111 67 ...
  ..$ 2:'data.frame':   50 obs. of  2 variables:
  .. ..$ X1: int [1:50] 42 105 73 72 36 69 110 43 118 121 ...
  .. ..$ X2: int [1:50] 23 81 96 52 97 42 82 102 89 89 ...
  ..$ 3:'data.frame':   50 obs. of  2 variables:
  .. ..$ X1: int [1:50] 67 128 78 105 32 41 19 86 69 120 ...
  .. ..$ X2: int [1:50] 116 85 55 1 110 96 67 101 73 48 ...
  ..$ 4:'data.frame':   50 obs. of  2 variables:
  .. ..$ X1: int [1:50] 20 104 33 83 73 24 23 129 44 69 ...
  .. ..$ X2: int [1:50] 13 100 74 14 0 59 55 80 72 2 ...
 $ BC_df:List of 4
  ..$ 1:'data.frame':   51 obs. of  2 variables:
  .. ..$ X1: int [1:51] 58 85 40 68 30 32 111 96 35 51 ...
  .. ..$ X2: int [1:51] 71 24 12 50 87 61 17 65 11 43 ...
  ..$ 2:'data.frame':   50 obs. of  2 variables:
  .. ..$ X1: int [1:50] 10 54 91 105 65 39 26 78 123 12 ...
  .. ..$ X2: int [1:50] 117 31 6 114 73 11 58 93 106 21 ...
.........................................................

data:

set.seed(0L)    
AB_df = data.frame(replicate(2,sample(0:130,201,rep=TRUE)))
BC_df = data.frame(replicate(2,sample(0:130,200,rep=TRUE)))
DE_df = data.frame(replicate(2,sample(0:130,197,rep=TRUE)))
FG_df = data.frame(replicate(2,sample(0:130,203,rep=TRUE)))

AB_pc = data.frame(replicate(2,sample(0:130,201,rep=TRUE)))
BC_pc = data.frame(replicate(2,sample(0:130,200,rep=TRUE)))
DE_pc = data.frame(replicate(2,sample(0:130,197,rep=TRUE)))
FG_pc = data.frame(replicate(2,sample(0:130,203,rep=TRUE)))

df_list = list(AB_df, BC_df, DE_df, FG_df, AB_pc, BC_pc, DE_pc, FG_pc)
names(df_list) = c("AB_df", "BC_df", "DE_df", "FG_df", "AB_pc", "BC_pc", "DE_pc", "FG_pc")
chinsoon12
  • 25,005
  • 4
  • 25
  • 35
  • Thank you! I am going to try this. – Mr.Spock Oct 09 '19 at 11:32
  • How can I define n. It should be the number of rows, right? – Mr.Spock Oct 09 '19 at 14:38
  • 1
    sorry abt that. have fixed it – chinsoon12 Oct 09 '19 at 23:43
  • One more question. This seems to work exactly how I want. But in my real df I often only get 3 subsets for some dataframes, even though I devide through 4...any idea why? I updated my dataframe in my answer, please have a look. When I use a different number of rows, there are only 3 dataframes in AB_df... – Mr.Spock Oct 10 '19 at 11:47
  • Oh and also I am not totally getting the right numbers. When I have 1624 observations and want 5 subsets, I am getting observations of 325 and 4x 324, which is only 1621 in total. – Mr.Spock Oct 10 '19 at 12:27
  • Not in front of computer. Can you try seq(1,n*(1+1/n),by=ceiling(n/5)) – chinsoon12 Oct 10 '19 at 13:26
  • No that still doesnt work. The problem is that my sequence as to end on the exact nrow...and it doesnt, it stops before and so some data is missing. – Mr.Spock Oct 10 '19 at 13:45
  • 1
    sorry had a typo. I meant `n <- 1624; k <- 5; lengths(split(1:n, cut(1:n, seq(0, n*(1+1/k), by=ceiling(n/k)))))`. have fixed it in the code above – chinsoon12 Oct 10 '19 at 21:44