2017-06-14 91 views
4

我有一个简单的问题,它可以在一个肮脏的方式来解决,但是我正在寻找使用清洁的方式data.table随机抽样基于列组

我有以下data.tablen列属于不平等的群体。这里是我的data.table的例子:

dframe <- as.data.frame(matrix(rnorm(60), ncol=30)) 
cletters <- rep(c("A","B","C"), times=c(10,14,6)) 
colnames(dframe) <- cletters 


      A   A   A   A   A   A 
1 -0.7431185 -0.06356047 -0.2247782 -0.15423889 -0.03894069 0.1165187 
2 -1.5891905 -0.44468389 -0.1186977 0.02270782 -0.64950716 -0.6844163 
      A   A   A   A   B   B   B 
1 -1.277307 1.8164195 -0.3957006 -0.6489105 0.3498384 -0.463272 0.8458673 
2 -1.644389 0.6360258 0.5612634 0.3559574 1.9658743 1.858222 -1.4502839 
      B   B   B   B   B   B   B 
1 0.3167216 -0.2919079 0.5146733 0.6628149 0.5481958 -0.01721261 -0.5986918 
2 -0.8104386 1.2335948 -0.6837159 0.4735597 -0.4686109 0.02647807 0.6389771 
      B   B   B   B   C   C 
1 -1.2980799 0.3834073 -0.04559749 0.8715914 1.1619585 -1.26236232 
2 -0.3551722 -0.6587208 0.44822253 -0.1943887 -0.4958392 0.09581703 
      C   C   C   C 
1 -0.1387091 -0.4638417 -2.3897681 0.6853864 
2 0.1680119 -0.5990310 0.9779425 1.0819789 

我想要做的是采取列(一sepcific大小)的随机子集,保持相同的每列组(如果选择的样本大小大于属于一个组的列数,取这个组的所有列)。

我试图在这个问题中提到的方法的更新版本:

sample rows of subgroups from dataframe with dplyr

,但我不能够将列名映射到by说法。

有人可以帮助我吗?

+0

不清楚给我。你想要一个子集,但每个组的列数保持不变?你的意思是你只是想随机排列这些列吗?请澄清 –

+0

@docendodiscimus如果随机样本大小大于每个组的实际列数,则列数应该保持不变。例如,在示例数据框中,假设样本大小为7,结果data.table应包括属于A的7个随机列,属于B的7个随机列和属于C的所有列(因为C只有6列属于它,这是比选择的样本大小) – ifreak

回答

4

这里的另一种方法,IIUC:

idx <- split(seq_along(dframe), names(dframe)) 
keep <- unlist(Map(sample, idx, pmin(7, lengths(idx)))) 

dframe[, keep] 

说明:

第一步根据列名拆分列索引:

idx 
# $A 
# [1] 1 2 3 4 5 6 7 8 9 10 
# 
# $B 
# [1] 11 12 13 14 15 16 17 18 19 20 21 22 23 24 
# 
# $C 
# [1] 25 26 27 28 29 30 

在下一步骤中,我们使用

pmin(7, lengths(idx)) 
#[1] 7 7 6 

,以确定各组中的样本大小,并使用在Mapidx将此到每个列表元素(组)。然后,我们将结果取消列表以获得列索引的单个向量。

+0

似乎工作得很好,你能向我解释一下代码吗?因为有功能我从来没有用过。 – ifreak

0

不知道,如果你想与dplyr一个解决方案,但这里有一个只有lapply

dframe <- as.data.frame(matrix(rnorm(60), ncol=30)) 
cletters <- rep(c("A","B","C"), times=c(10,14,6)) 
colnames(dframe) <- cletters 

# Number of columns to sample per group 
nc <- 8 


res <- do.call(cbind, 
     lapply(unique(colnames(dframe)), 
       function(x){ 
         dframe[,if(sum(colnames(dframe) == x) <= nc) which(colnames(dframe) == x) else sample(which(colnames(dframe) == x),nc,replace = F)] 
         } 
)) 

它可能看起来很复杂,但它真的只是需要所有列每组如果有小于nc,和样品随机nc列,如果有多于nc列。

,并恢复原来的列名方案,GSUB的伎俩:

colnames(res) <- gsub('.[[:digit:]]','',colnames(res))

+0

这似乎工作,但res中的一些姓氏是随机的,并与原始列名称无关 – ifreak

+0

你是什么意思?我得到了染色体A - B - C,并附有一个整数,指出样品编号(第一个是A,第二个是A.1,等等)。借助'gsub'功能,您可以回到原来的A-B-C。 – Val

+0

我的专栏名称不仅包含A,B,C ......,还可以包含更多字符。我收到了这样的列名: 'c(0.2818491673,0.6562765283,0,0,0,5.318117652,0.66930066962,' – ifreak