【问题标题】:creating a matrix/dataframe with two for loops in R在 R 中创建一个带有两个 for 循环的矩阵/数据框
【发布时间】:2018-02-11 02:55:43
【问题描述】:

这是我关于 SO 的第一篇文章,请善待!

我的问题与这个模糊相关: Double for loop in R creating a matrix

我想创建一个矩阵/数据框,我选择的方法是嵌套两个 for 循环,一个用于创建第一行,第二个用于为我需要的行重复它。

我可以成功创建第一个循环,但我似乎无法迭代它以获得我需要的行数。

我确信有更好的方法可以做到这一点,无论如何,这是为第一行提供我需要的结果的 for 循环:

x <- character(0)
for(j in 1:18){
    x <- c(x, sum(it_mat[1, 2:26] == j))
}

it_mat 是一个 417 行 26 列的矩阵,其中第一列是具有各种名称的字符串向量,随后的列是从 1 到 18 随机生成的数字。

这是第一行:

[1,] "Charlie" "14" "3"  "9"  "14" "3"  "9"  "11" "11" "18"  "17"  "16"  "5"   "18"  "6"   "10"  "3"   "9"   "9"   "3"   "18"  "12"  "8"   "5"   "5"  "4"

我想创建一个矩阵/df,在其中计算每个名称,每个数字出现的次数。

我在上面创建的 for 循环给了我想要的第一行结果:

x
[1] "0" "0" "4" "1" "3" "1" "0" "1" "4" "1" "2" "1" "0" "2" "0" "1" "1" "3"

我真的无法用另一个 for 循环对后续行进行迭代,一定是我做错了一些非常平凡的事情。

这是我最好的尝试:

tr_mat <- matrix(, nrow = 147, ncol = 18)
for(i in 1:147){
    x <- character()
    for(j in 1:18){
        x <- c(x, sum(it_mat[i, 2:26] == j))
    }
    tr_mat <- rbind(tr_mat, x)
}

我整个下午都在做,现在我放弃并联系你,在你给我正确的方法之前,请解释我在嵌套 for 循环中做错了什么尝试,我可能会学到一些东西.

我希望我解释了自己,如果我太冗长了,抱歉。 感谢您的宝贵时间。

【问题讨论】:

  • 对于那些投票关闭的人,您能否发表评论说明 OP 可以做些什么来改进。这是第一次发布海报,重要的是我们教导人们期望的行为,而不是完全阻止在 SO 上发帖。
  • tr_mat[i, ] &lt;- x,而不是tr_mat &lt;- rbind(tr_mat, x)。 (您正在绑定一个包含 147 个新行的 NAvalues 矩阵。)
  • 你能包含一个简短的 'it_mat' 的 sn-p 吗?在循环之前?
  • OP 在发布他的问题之前已经尽了最大的努力并付出了足够的努力。我们必须鼓励这样的新加入者!!
  • 我对 OP 的建议是让代码完全可重现会很棒。 OP 提供了很好的详细代码和一些所需的输出,但不清楚 it_mat 是什么。这就是我投票关闭这篇文章的原因。如果 OP 可以提供 it_mat 的可重现示例,我将撤回我的投票并给这篇文章投上一票。

标签: r data-structures


【解决方案1】:

@RuiBarradesh 在 OP 最后一次尝试中指出了实际问题。还有另一种方法可以使用rbind 修复 OP 代码。

# Do not create rows at this place. Let the rows be added with rbind
tr_mat <- matrix(nrow = 0, ncol = 18)   #(, nrow = 147, ncol = 18)
for(i in 1:147){
  x <- character()
  for(j in 1:18){
    x <- c(x, sum(it_mat[i, 2:26] == j))
  }
  tr_mat <- rbind(tr_mat, x)
}

tr_mat      # This will display correct result too

【讨论】:

  • 也谢谢你,如果我没有添加一个可重现的例子,我也很抱歉,但昨天我也被 sample() 玩弄了。我给了 it_mat 的第一行,认为它已经足够了。对此感到抱歉。无论如何,在 nrow 中有一个输入错误:它应该是 417 而不是 147。
【解决方案2】:

另一种方式,使用基础 R。请注意,*apply 函数是变相的循环。

tr_mat2 <- sapply(1:18, function(j) sapply(1:147, function(i) sum(it_mat[i, 2:26] == j)))

请注意,此代码将生成一个数字矩阵,而您的 tr_mat 是模式 character

all.equal(tr_mat, tr_mat2)
#[1] "Modes: character, numeric"

数据。
这是我用来测试上面代码的数据集生成代码。

set.seed(7966)    # make the results reproducible
it_mat <- t(replicate(147, c(sample(letters, 1), sample(18, 25, TRUE))))

编辑。
按照 MKR 在 cmets 中的建议,这里是 OP 的代码,我在对他(OP)帖子的评论中进行了修改。

tr_mat <- matrix(, nrow = 147, ncol = 18)
for(i in 1:147){
    x <- character()
    for(j in 1:18){
        x <- c(x, sum(it_mat[i, 2:26] == j))
    }
    tr_mat[i, ] <- x
}

这是我用来生成上述tr_mat 测试中提到的矩阵tr_mat 的代码。

【讨论】:

  • 感谢您的帮助,我采用了您的解决方案,因为我自己几乎以同样的方式解决了它,但我没有正确嵌套它。我实际上比 R 中的循环更熟悉 apply 系列(尤其是 tapply,非常适合研究数据库),但最近我一直在使用 Python...
【解决方案3】:

你真的需要 2 个循环吗?这是一个没有任何循环的解决方案,使用 data.table 和 melt/dcast 函数的组合:

library(data.table)

# dataset ----------------------------
seed(2018)

it_mat<-data.frame(c1=c('Charlie','John','Peter'))

for(i in 2:26){
  it_mat[,paste0('c',i)]<-sample(1:18,3)
}

# calculation ----------------------------

it_mat<-data.table(it_mat)
it_mat<-melt(it_mat,id.vars='c1')
it_mat[,.N,by=.(c1,value)][order(c1,value)]

dcast(it_mat[,.N,by=.(c1,value)][order(c1,value)],c1~value)

【讨论】:

  • 感谢您的建议,但我对 data.table 不熟悉。我不喜欢使用替换基本 R 函数的包,因为作为一个新手,如果你明白我的意思,我认为以艰苦的方式学习排骨更有教育意义。感谢您的意见,无论如何感谢。
猜你喜欢
  • 2020-05-25
  • 2022-07-19
  • 2017-11-22
  • 2018-01-16
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多