【问题标题】:Outputting nested loops in sucessive columns在连续列中输出嵌套循环
【发布时间】:2018-02-14 15:53:11
【问题描述】:

我是循环的新手,我正在努力格式化我的输出。我正在尝试将多个物种 (k) 的不同时间点 (i) 的物种丰度时间序列修改为不同的量级 (j)。对于这些选项中的每一个,我都想要一个显示随时间变化的丰度的列。

我编写了一个循环,当我手动输入 i、j 和 k 的各种值(即我得到具有正确值的单列)时,该循环可以工作,但我不知道如何正确索引输出矩阵。

一个虚拟数据集如下所示(其中 x 和 y 是不同的物种,样本数是时间):

dat<- data.frame(x = sample(1:100, 100, replace = TRUE), y = sample(1:100, 100, replace = TRUE))

对于我的循环,我还创建了一些其他对象:

length <- nrow(dat)
change <- as.matrix(seq(0.0,0.99,0.2))
change.length <- nrow(change)

以及要填充的最终矩阵(具有正确的尺寸)。 -40 在那里是因为我没有修改时间序列中的前 20 个或后 20 个丰度

final_matrix <- array(0,c(length,(((length-40)*change.length)*2))) # 2 is the number of species in this example

循环如下所示:

for(i in 1:(length-40)) {
  for(j in 1:change.length){
    for(k in 1:2){
timestep1 <- dat[0:(19+(i)),k]   # selecting rows that will not be modified based on min + i for a given species k
timestep2 <- dat[(20+i):(length),k] # selecting rows that will be modified for any given species k (columns)

 result1 <- timestep1*1 # not making any changes to the abundance data
 result2 <- timestep2*change[j,1] # multiplying abundance by change (j)

 resultloop<-c(result1,result2) # binding the two matrices into a single column with 100 rows

 final_matrix[,i*j*k] <- resultloop
}}}

按原样索引的最终矩阵会产生不正确的列数,并产生奇怪的结果,例如全为零的列。

如何索引这个矩阵,以便每列(100 行表示随时间变化的丰度)都为 i、j 和 k 的每个值编制索引?

编辑:一个示例(模拟)虚拟数据集,用于说明我希望输出的样子:

dat<- data.frame(Spx_I1_j1 = sample(1:100, 100, replace = TRUE),
             Spx_I2_j1 = sample(1:100, 100, replace = TRUE),
             Spx_I3_j1 = sample(1:100, 100, replace = TRUE),
             # etc...
             Spx_I1_k2 = sample(1:100, 100, replace = TRUE),
             Spx_I2_k2 = sample(1:100, 100, replace = TRUE),
             #etc...
             Spy_I1_k1 = sample(1:100, 100, replace = TRUE),
             Spy_I2_k1 = sample(1:100, 100, replace = TRUE))

其中 100 个丰度值的每一列由每个修改的时间步长序列 (i) 对于每个物种 (k) 的每个幅度变化 (j) 的单独列表示。

非常感谢您在此问题上提供的任何帮助或建议。

【问题讨论】:

  • 请展示预期输出的样本
  • 感谢您的评论@waterling。我希望提供的虚拟数据集能够充分说明我希望最终输出的样子。如果您需要任何进一步的信息,请告诉我。
  • 您将结果放入列i*j*k。在for(k in 1:2){ 之后添加print(i*j*k) 并查看结果应该写入哪一列。这真的是正确的列吗?您还可以在最后一个 for 循环中插入 browser() 以了解发生了什么。
  • 谢谢@Roman。在我的问题中,我将输出放在i*j*k 列中,但我认为这是完全错误的。我的问题是,是否有人有解决方案允许我通过为所有循环建立索引来将所有迭代存储在列中?
  • 不太确定我是否理解您的问题,但我可以建议像array(dim = c(2, length, length - 40, change.length), dimnames = list( species = c("x", "y"), sample_number = NULL, time_point = NULL, magnitude = NULL ))(多维数组)这样的东西作为更合适的数据结构吗?

标签: r for-loop indexing nested-loops


【解决方案1】:

我不太确定你在问什么。这是我的解释。 顺便说一句,请查看How to make a great R reproducible example? 以在将来重新提出您的问题。

#Make some sample data, 10 observations, ignore the first 2 and last 2

ss<-function(x,n){set.seed(x); sample(1:100,n,replace=TRUE)}
dat<-as.matrix(data.frame("Dog"=ss(1,10),"Cat"=ss(2,10))) #Note, make this a matrix!
ind_ignore<-c(1:2,9:10) #these will be ignored, like your first and last x abundances
change <- seq(0.0,0.99,0.2) #5 values, so the expected output is expected to have a dimension of 10 obs by (2 species * 5 changes)
result <- matrix(NA,ncol=ncol(dat)*length(change), nrow=nrow(dat))
colnames(result)<-paste0("V",1:ncol(result))
n_counter<-ncol(dat)-1
counter<-1

> change
[1] 0.0 0.2 0.4 0.6 0.8
> dat
      Dog Cat
 [1,]  27  19
 [2,]  38  71
 [3,]  58  58
 [4,]  91  17
 [5,]  21  95
 [6,]  90  95
 [7,]  95  13
 [8,]  67  84
 [9,]  63  47
[10,]   7  55

然后我只是将 dat 值分配给结果矩阵,并更改 colnames。

for(magnitude in change){
  #Indexes of columns in result that should be modified
  ind_col<-counter:(counter+n_counter)

  #Change names
  colnames(result)[ind_col]<-paste0(colnames(dat),"_",magnitude)

  #Apply the change and assign it to the result
  result[-ind_ignore,ind_col]<-dat[-ind_ignore,]*magnitude
  result[ind_ignore,ind_col]<-dat[ind_ignore,]

  counter<-counter+ncol(dat)
}

输出

> result
      Dog_0 Cat_0 Dog_0.2 Cat_0.2 Dog_0.4 Cat_0.4 Dog_0.6 Cat_0.6 Dog_0.8 Cat_0.8
 [1,]    27    19    27.0    19.0    27.0    19.0    27.0    19.0    27.0    19.0
 [2,]    38    71    38.0    71.0    38.0    71.0    38.0    71.0    38.0    71.0
 [3,]     0     0    11.6    11.6    23.2    23.2    34.8    34.8    46.4    46.4
 [4,]     0     0    18.2     3.4    36.4     6.8    54.6    10.2    72.8    13.6
 [5,]     0     0     4.2    19.0     8.4    38.0    12.6    57.0    16.8    76.0
 [6,]     0     0    18.0    19.0    36.0    38.0    54.0    57.0    72.0    76.0
 [7,]     0     0    19.0     2.6    38.0     5.2    57.0     7.8    76.0    10.4
 [8,]     0     0    13.4    16.8    26.8    33.6    40.2    50.4    53.6    67.2
 [9,]    63    47    63.0    47.0    63.0    47.0    63.0    47.0    63.0    47.0
[10,]     7    55     7.0    55.0     7.0    55.0     7.0    55.0     7.0    55.0

编辑

再次,我不知道我是否正确理解了 cmets,这里什么都没有:

ss<-function(x,n){set.seed(x); sample(1:100,n,replace=TRUE)}
dat<-as.matrix(data.frame("Dog"=ss(1,10),"Cat"=ss(2,10))) #Note, make this a matrix!
ignore<-2 #these will be ignored, like your first and last x abundances
change <- seq(0.0,0.99,0.2) #5 values, so the expected output is expected to have a dimension of 10 obs by (2 species * 5 changes * (10-4 ignored points) timepoints)
n_timepoints<-nrow(dat) - ignore*2
result <- matrix(NA,ncol=ncol(dat)*length(change)*n_timepoints, nrow=nrow(dat))
colnames(result)<-paste0("V",1:ncol(result))
n_counter<-ncol(dat)*n_timepoints-1
counter<-1

for(magnitude in change){
  #Indexes of columns in result that should be modified
  ind_col<-counter:(counter+n_counter)

  #Change names
  colnames(result)[ind_col]<-paste0(colnames(dat),"_",magnitude,"_",rep(1:n_timepoints, each=ncol(dat)))

  for (timepoint in 1:n_timepoints){
    #Apply the change and assign it to the result
    ind_col_timepoint <- counter:(counter+ncol(dat)-1)
    ind_ignore_timepoint<-c(1:(ignore+timepoint-1), (nrow(dat)-ignore+1):nrow(dat))
    result[-ind_ignore_timepoint,ind_col_timepoint]<-dat[-ind_ignore_timepoint,]*magnitude
    result[ind_ignore_timepoint,ind_col_timepoint]<-dat[ind_ignore_timepoint,]
    counter<-counter+ncol(dat)
  }

}

【讨论】:

  • 谢谢你!我为我的笨拙问题道歉(第一次发帖)。您的解决方案几乎是完美的。但是我在代码中需要的主要方面之一是更改发生在不同的时间(在我的示例中标记为i)。例如Dog_0 应该有 6 列,变化发生在 3:8 行中;然后是 4:8;然后是 5:8 等。有没有办法将它集成到您​​提供的代码中?
  • 我不明白。我以为i 指的是每一行
  • 你是对的 i 指的是每一行。但我想在不同时间创建更改。所以你的 Dog_0 列对于 i =1 是正确的(例如更改发生在 3:8 时间)但我还想要另一列 i = 2(例如更改发生在时间 4:8)和 i = 3(5:8 变化)等
  • 太棒了 - 这很有效。我还没有完全理解代码,但我会到达那里。非常感谢您的时间和耐心!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-20
  • 1970-01-01
  • 2015-03-29
  • 2015-03-10
  • 1970-01-01
  • 1970-01-01
  • 2010-11-11
相关资源
最近更新 更多