如何按行和按列随机化(或置换)数据框?
Posted
技术标签:
【中文标题】如何按行和按列随机化(或置换)数据框?【英文标题】:How to randomize (or permute) a dataframe rowwise and columnwise? 【发布时间】:2011-09-19 07:40:00 【问题描述】:我有一个这样的数据框 (df1)。
f1 f2 f3 f4 f5
d1 1 0 1 1 1
d2 1 0 0 1 0
d3 0 0 0 1 1
d4 0 1 0 0 1
d1...d4 列是行名,f1...f5 行是列名。
为了做样本(df1),我得到一个与 df1 相同的计数为 1 的新数据帧。因此,1 的计数对于整个数据帧是保留的,但不是对于每一行或每一列。
是否可以按行或按列进行随机化?
我想为每列随机化 df1 列,即每列中 1 的数量保持不变。并且每列至少需要更改一次。例如,我可能有一个这样的随机 df2:(请注意,每列中 1 的计数保持不变,但每行中 1 的计数不同。
f1 f2 f3 f4 f5
d1 1 0 0 0 1
d2 0 1 0 1 1
d3 1 0 0 1 1
d4 0 0 1 1 0
同样,我还想为每一行随机化 df1 行,即 no。每行中的 1 保持不变,并且每一行都需要更改(但更改的条目数可能不同)。例如,随机 df3 可能是这样的:
f1 f2 f3 f4 f5
d1 0 1 1 1 1 <- two entries are different
d2 0 0 1 0 1 <- four entries are different
d3 1 0 0 0 1 <- two entries are different
d4 0 0 1 0 1 <- two entries are different
PS。非常感谢 Gavin Simpson、Joris Meys 和 Chase 对我之前关于随机两列的问题的回答。
【问题讨论】:
您是否要同时置换行 和 列。重读这篇文章,看起来列约束(每列中相同数量的 1)在您的第二个置换行示例中不成立。 请不要注册多个帐户。我已要求版主将您在此处使用的帐户与上一个 Q 中使用的帐户合并。 【参考方案1】:当然你可以对每一行进行采样:
sapply (1:4, function (row) df1[row,]<<-sample(df1[row,]))
会自行打乱行,因此每行中1
的数量不会改变。小的变化,它也适用于列,但这是给读者的练习:-P
【讨论】:
没有任何东西试图实现 OP 想要施加的约束。【参考方案2】:看看 vegan 包中的 permatswap()
。这是一个同时维护行总计和列总计的示例,但您可以放宽它并仅修复行或列总计中的一个。
mat <- matrix(c(1,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,1), ncol = 5)
set.seed(4)
out <- permatswap(mat, times = 99, burnin = 20000, thin = 500, mtype = "prab")
这给出了:
R> out$perm[[1]]
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 1 1 1
[2,] 0 1 0 1 0
[3,] 0 0 0 1 1
[4,] 1 0 0 0 1
R> out$perm[[2]]
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 0 1 1
[2,] 0 0 0 1 1
[3,] 1 0 0 1 0
[4,] 0 0 1 0 1
解释调用:
out <- permatswap(mat, times = 99, burnin = 20000, thin = 500, mtype = "prab")
times
是你想要的随机矩阵的数量,这里是 99
burnin
是在我们开始随机抽样之前进行的交换次数。这允许我们从中采样的矩阵在开始获取每个随机矩阵之前是非常随机的
thin
表示只在每一次 thin
交换时随机抽奖
mtype = "prab"
表示将矩阵视为存在/不存在,即二进制 0/1 数据。
有几点需要注意,这并不能保证任何列或行都已随机化,但如果burnin
足够长,则很有可能发生这种情况。此外,您可以绘制比您需要的更多的随机矩阵,并丢弃不符合您所有要求的随机矩阵。
您要求每行有不同数量的更改,这里也没有涵盖。同样,您可以采样比您想要的更多的矩阵,然后也丢弃不满足此要求的矩阵。
【讨论】:
【参考方案3】:给定 R data.frame:
> df1
a b c
1 1 1 0
2 1 0 0
3 0 1 0
4 0 0 0
按行随机播放:
> df2 <- df1[sample(nrow(df1)),]
> df2
a b c
3 0 1 0
4 0 0 0
2 1 0 0
1 1 1 0
默认情况下sample()
随机重新排序作为第一个参数传递的元素。这意味着默认大小是传递数组的大小。将参数 replace=FALSE
(默认值)传递给 sample(...)
可确保在不替换的情况下完成采样,从而实现逐行随机播放。
按列随机播放:
> df3 <- df1[,sample(ncol(df1))]
> df3
c a b
1 0 1 1
2 0 1 0
3 0 0 1
4 0 0 0
【讨论】:
我觉得这不是***评论很有趣,但它比去学习其他包要简单。几乎所有关于置换的问题都是如此。只需使用 SAMPLE()! 我是否正确假设此方法将维护 row.names? 有什么理由在标准上使用 = 嗯,这是改变行和列的顺序,但是 OP 想要的是不同的:独立地洗牌每一列/行 正是我需要的!【参考方案4】:你也可以使用R包中的randomizeMatrix
函数picante
示例:
test <- matrix(c(1,1,0,1,0,1,0,0,1,0,0,1,0,1,0,0),nrow=4,ncol=4)
> test
[,1] [,2] [,3] [,4]
[1,] 1 0 1 0
[2,] 1 1 0 1
[3,] 0 0 0 0
[4,] 1 0 1 0
randomizeMatrix(test,null.model = "frequency",iterations = 1000)
[,1] [,2] [,3] [,4]
[1,] 0 1 0 1
[2,] 1 0 0 0
[3,] 1 0 1 0
[4,] 1 0 1 0
randomizeMatrix(test,null.model = "richness",iterations = 1000)
[,1] [,2] [,3] [,4]
[1,] 1 0 0 1
[2,] 1 1 0 1
[3,] 0 0 0 0
[4,] 1 0 1 0
>
选项null.model="frequency"
维护列总和,richness
维护行总和。
虽然主要用于群落生态中的物种存在缺失数据集的随机化,但它在这里运行良好。
此功能还有其他空模型选项,请查看以下链接了解更多详情(第 36 页) picante
documentation
【讨论】:
【参考方案5】:数据帧中的随机样本和排列 如果是矩阵形式,则转换为 data.frame 使用基础包中的示例函数 索引 = 样本(1:nrow(df1), size=1*nrow(df1)) 随机样本和排列
【讨论】:
【参考方案6】:这是使用包dplyr
洗牌data.frame
的另一种方法:
逐行:
df2 <- slice(df1, sample(1:n()))
或
df2 <- sample_frac(df1, 1L)
按列:
df2 <- select(df1, one_of(sample(names(df1))))
【讨论】:
【参考方案7】:您还可以通过以下方式“采样”数据框中相同数量的项目:
nr<-dim(M)[1]
random_M = M[sample.int(nr),]
【讨论】:
你可以使用nrow(M)
而不是dim(M)[1]
,这样整个过程就变成了一个单行:random_M <- M[nrow(M),]
【参考方案8】:
如果目标是随机打乱每列,则上述某些答案不起作用,因为列是联合打乱的(这保留了列间的相关性)。其他需要安装软件包。然而存在单行:
df2 = lapply(df1, function(x) sample(x) )
【讨论】:
以上是关于如何按行和按列随机化(或置换)数据框?的主要内容,如果未能解决你的问题,请参考以下文章