【问题标题】:Sampling a contingency table in R在 R 中对列联表进行采样
【发布时间】:2014-09-12 01:59:48
【问题描述】:

我想知道是否有人可以建议一种有效的方法来对列联表进行抽样,以使观察总数和列总数保持不变。

例如,在下表中,行是案例,列是观察,我想“打乱”观察,使得 (a) 观察总数为 54,(b) 总数变量(例如 A)中的观察值是 16 18,与 A 的原始列总数相同。

x<-matrix(c(
4,6,0,0,8,0,0,
1,1,1,1,4,0,0,
3,0,1,1,6,0,1,
2,1,0,0,1,0,0,
1,1,0,1,0,1,1,
2,0,0,2,1,2,0),
ncol=6,byrow=F)

colnames(x)<-c("A","B","C","D","E","F")

我看到了关于列联表采样的讨论,其中单元格频率是 sample(...) 调用的采样概率的来源。这不适用于我的目的,因为除其他原因外,列总数不等于原始列总数。

任何帮助将不胜感激, 帕特里克

编辑

如果这个问题没有简单的解决方案,也许有人可以帮助我解决我过于复杂(且失败)的尝试。我首先创建一个由每个变量的观察次数组成的向量,例如,

m <- matrix()
v <- matrix()
for (h in 1:cols) {
    m <- rep(colnames(x)[h], sum(x[, h]))
    v <- c(v, m)}

然后我对其进行采样以随机打乱观察结果,并将其绑定到等于案例数量的值样本

    v<-sample(v,length(v))
    p<-sample(seq(1:nrow(x)),length(v),T)
    n<-as.data.frame(cbind(v,p))

    t(table(n))

      v
    p A B C D E F
    1 3 1 3 1 1 1
    2 1 1 0 0 0 0
    3 3 0 3 0 2 1
    4 3 2 1 2 1 2
    5 2 1 0 0 0 1
    6 3 2 3 1 1 1
    7 3 1 2 0 0 1

    colSums(t(table(n)))
    A  B  C  D  E  F 
   18  8 12  4  5  7 

这很有效,除非样本 p 未能包含序列中的一个值(即“案例”缺失),据我所知,这种情况经常发生,特别是当样本(例如,1000 个)。

再次感谢, 帕特里克

【问题讨论】:

  • sum(x[,"A"]) 根据我的计算是 18 不是 16。
  • 看起来这可能会有所帮助:stackoverflow.com/questions/12031049/…
  • 感谢@thelatemail 的建议(和更正),但我不清楚这种方法是如何工作的。不保留列总计(我需要此功能)和行总计(我不想要此功能)。
  • @user1596424 您对the first row of column A should be able to have values from 1 to 18 的评论与您显示的评论不同。也许我误解了。此外,如果您希望列 A 的值介于 1 到 18 之间,是否可以重复。
  • @user1596424 我更新了代码。

标签: r


【解决方案1】:

另一种方法是:

indx <- cbind(c(replicate(ncol(x), sample(1:nrow(x)))), c(col(x)))
x1 <- x
x1[] <- x[indx]
 
colSums(x1)
# A  B  C  D  E  F 
#18  8 12  4  5  7 

colSums(x)
#A  B  C  D  E  F 
#18  8 12  4  5  7 

sum(x1)
#[1] 54

更新

根据令人困惑的新信息,这可能会有所帮助:

 cSum <- colSums(x)
 ind1 <- vector("list", length=ncol(x))
 for(i in seq_along(cSum)){
 repeat{ind1[[i]] <- sample(0:cSum[i], nrow(x)-1, replace=TRUE)
 if(sum(ind1[[i]]) <=cSum[i]) break
  }
 }

 x1 <- do.call(cbind, ind1)
 x2 <- rbind(x1,cSum-colSums(x1))
 colSums(x2)
# A  B  C  D  E  F 
#18  8 12  4  5  7 

sum(colSums(x2))
#[1] 54

  x2
 #    A B C D E F
 #[1,] 0 0 0 0 0 0
 #[2,] 9 5 1 2 0 1
 #[3,] 0 1 1 1 0 2
 #[4,] 0 0 4 0 0 1
 #[5,] 8 0 5 0 4 2
 #[6,] 0 0 1 0 1 1
 #[7,] 1 2 0 1 0 0

【讨论】:

  • 谢谢大家,但不幸的是,您的建议和下面@nico 的建议都不起作用。我需要它来改变观察结果,而不是案例。例如,A 列的第一行应该能够具有从 1 到 18 的值。对于 A 的其余行也是如此,但它们的总和必须为 18。
  • @user1596424 对不起,我在关注你。如果A 列可能有来自1 to 18 的值,我猜,B 列应该有1 to 8 和其他列类似。所以,colSums 只重要,column values 不重要?
  • 太棒了!谢谢@akrun,这正是我所需要的。
【解决方案2】:

你可以使用

x.swapped <- apply(x, MARGIN=2, FUN=sample)

apply 将参数FUN 中传递的函数应用于矩阵x 的列(如果MARGIN 为2,则为1 时为行)。
在这种情况下,我们应用 sample 函数。
在不带额外参数的情况下调用 sample 只会重新排序向量中的元素(请参阅 ?sample 以获得更多帮助)。

我们可以检查每一列的总数是否保持不变。

colSums(x)

 A  B  C  D  E  F 
18  8 12  4  5  7 

colSums(x.swapped)
 A  B  C  D  E  F 
18  8 12  4  5  7 

显然

sum(x)
[1] 54

sum(x.swapped)
[1] 54

一个输出示例可能是(请注意,除非您使用set.seed 修复RNG 种子,否则sample 的结果每次都会不同)。

x

     A B C D E F
[1,] 4 1 3 2 1 2
[2,] 6 1 0 1 1 0
[3,] 0 1 1 0 0 0
[4,] 0 1 1 0 1 2
[5,] 8 4 6 1 0 1
[6,] 0 0 0 0 1 2
[7,] 0 0 1 0 1 0

x.swapped

     A B C D E F
[1,] 6 4 1 0 1 0
[2,] 0 1 3 2 0 0
[3,] 0 0 1 1 1 2
[4,] 0 0 0 0 1 2
[5,] 8 1 1 1 1 2
[6,] 4 1 0 0 1 0
[7,] 0 1 6 0 0 1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-25
    • 2014-02-24
    • 2021-11-02
    • 1970-01-01
    • 2020-03-12
    • 1970-01-01
    相关资源
    最近更新 更多