【问题标题】:Vectorize indexing with for loop使用 for 循环矢量化索引
【发布时间】:2017-07-22 20:00:55
【问题描述】:

我正在尝试模拟装配线。我有一份零件清单以及它们在每个站点花费的时间。我试图一次通过装配线发送一个零件并记录每个站点的时间。但是,我的工作方式是使用嵌套在 for 循环内的 for 循环。必须有更好的方法来做到这一点。

parts <- data.frame(JobNum = sample(c('a','b','c','d'),400,replace=TRUE)
,DS.CT = sample.int(10,400,replace=TRUE)
,C1.CT = sample.int(10,400,replace=TRUE)
,C2.CT = sample.int(10,400,replace=TRUE)
,C3.CT = sample.int(10,400,replace=TRUE)
,C4.CT = sample.int(10,400,replace=TRUE)
,C5D5.CT = sample.int(10,400,replace=TRUE)
,C6D6.CT = sample.int(10,400,replace=TRUE)
,C5D7.CT = sample.int(10,400,replace=TRUE)
,C6D8.CT = sample.int(10,400,replace=TRUE)
,C7CD.CT = sample.int(10,400,replace=TRUE)
)

LineParts <- parts[sample(nrow(parts),234,replace=FALSE),]

#Initialize Dip collecting variables
DS <- c()
D1 <- c()
D2 <- c()
D3 <- c()
D4 <- c()
D5 <- c()
D6 <- c()
D7 <- c()
D8 <- c()
D9 <- c()

for(i in 1:dim(parts)[1]){

#Create temporary dataframe for use in indexing line
LinePartsTemp <- data.frame(matrix("",nrow=234,ncol=11))
colnames(LinePartsTemp)=names(LineParts)
LinePartsTemp$JobNum <- as.character(LinePartsTemp$JobNum)
LinePartsTemp$DS.CT <- as.integer(LinePartsTemp$DS.CT)
LinePartsTemp$C1.CT <- as.integer(LinePartsTemp$C1.CT)
LinePartsTemp$C2.CT <- as.integer(LinePartsTemp$C2.CT)
LinePartsTemp$C3.CT <- as.integer(LinePartsTemp$C3.CT)
LinePartsTemp$C4.CT <- as.integer(LinePartsTemp$C4.CT)
LinePartsTemp$C5D5.CT <- as.integer(LinePartsTemp$C5D5.CT)
LinePartsTemp$C6D6.CT <- as.integer(LinePartsTemp$C6D6.CT)
LinePartsTemp$C5D7.CT <- as.integer(LinePartsTemp$C5D7.CT)
LinePartsTemp$C6D8.CT <- as.integer(LinePartsTemp$C6D8.CT)
LinePartsTemp$C7CD.CT <- as.integer(LinePartsTemp$C7CD.CT)

#Index line
for(j in 1:dim(LineParts)[1]){
    LinePartsTemp[j+1,] <- LineParts[j,]
}

#put new part into system
LinePartsTemp[1,] <- parts[i,]

#update the list of parts on the line
LineParts <- LinePartsTemp

#Append CT values at stations
DS <- append(DS,LineParts[1,'DS.CT'])
D1 <- append(D1,LineParts[10,'C1.CT'])
D2 <- append(D2,LineParts[26,'C2.CT'])
D3 <- append(D3,LineParts[42,'C3.CT'])
D4 <- append(D4,LineParts[57,'C4.CT'])
D5 <- append(D5,LineParts[85,'C5D5.CT'])
D6 <- append(D6,LineParts[120,'C6D6.CT'])
D7 <- append(D7,LineParts[167,'C5D7.CT'])
D8 <- append(D8,LineParts[210,'C6D8.CT'])
D9 <- append(D9,LineParts[234,'C7CD.CT'])

}

编辑:添加示例数据

【问题讨论】:

  • 您需要阅读?lapply 以节省大量代码。你可以做LinePartsTemp[c("var1","var2")] &lt;- lapply(LinePartsTemp[c("var1","var2")], as.integer)之类的事情,而不是重复的任务。另外,如果你提供一个带有一些简化数据的可重复的例子,你将更有可能得到答案。
  • 谢谢,我添加了一些示例数据,并将查看 lapply。

标签: r for-loop vector vectorization


【解决方案1】:

考虑与列表交互,以避免初始化空容器并在以后使用大量独立的环境对象附加到它们。除了输入之外,下面仅使用了两个对象。

  1. 首先,构建 LineParts 数据框列表,LineParts_dfList
  2. 然后,将所需的数据点提取到向量列表中,stations_veclist

您会注意到数据框列表的 lapply 使用 &lt;&lt;- 运算符来更新全局对象(本地函数范围之外),因为 LineParts 需要与更新的值一起重用:

LineParts_dfList <- lapply(seq(nrow(parts)), function(i){      
  #Index line
  LinePartsTemp <- parts[1,]
  LinePartsTemp[2:nrow(LineParts),] <- LineParts[1:nrow(LineParts)-1,]

  #put new part into system
  LinePartsTemp[1,] <- parts[i,]

  #update the list of parts on the line
  LineParts <<- LinePartsTemp      
})

# Extract CT values at stations
stations_veclist <- 
  list(
    DS = vapply(LineParts_dfList, function(df) df[1,'DS.CT'], numeric(1)),
    D1 = vapply(LineParts_dfList, function(df) df[10,'C1.CT'], numeric(1)),
    D2 = vapply(LineParts_dfList, function(df) df[26,'C2.CT'], numeric(1)),
    D3 = vapply(LineParts_dfList, function(df) df[42,'C3.CT'], numeric(1)),
    D4 = vapply(LineParts_dfList, function(df) df[57,'C4.CT'], numeric(1)),
    D5 = vapply(LineParts_dfList, function(df) df[85,'C5D5.CT'], numeric(1)),
    D6 = vapply(LineParts_dfList, function(df) df[120,'C6D6.CT'], numeric(1)),
    D7 = vapply(LineParts_dfList, function(df) df[167,'C5D7.CT'], numeric(1)),
    D8 = vapply(LineParts_dfList, function(df) df[210,'C6D8.CT'], numeric(1)),
    D9 = vapply(LineParts_dfList, function(df) df[234,'C7CD.CT'], numeric(1))
  )

为了避免许多 vapply 调用,请考虑将所有 LineParts 数据框项绑定到一个大数据框 LinePartsAll(N=93,600 obs,对于 234 X 400),然后按行顺序提取值:

LinePartsAll <- do.call(rbind, LineParts_dfList)

otherstations_veclist <- 
  list(
    DS = LinePartsAll[seq(1,93600, by=234),'DS.CT'],
    D1 = LinePartsAll[seq(10,93600, by=234),'C1.CT'],
    D2 = LinePartsAll[seq(26,93600, by=234),'C2.CT'],
    D3 = LinePartsAll[seq(42,93600, by=234),'C3.CT'],
    D4 = LinePartsAll[seq(57,93600, by=234),'C4.CT'],
    D5 = LinePartsAll[seq(85,93600, by=234), 'C5D5.CT'],
    D6 = LinePartsAll[seq(120,93600, by=234), 'C6D6.CT'],
    D7 = LinePartsAll[seq(167,93600, by=234),'C5D7.CT'],
    D8 = LinePartsAll[seq(210,93600, by=234), 'C6D8.CT'],
    D9 = LinePartsAll[seq(234,93600, by=234), 'C7CD.CT']
  )

并且检查一下,这个更新的、更快的方法确实会重现与原始双 for 循环过程相同的最终值。要使用发布的样本数据进行测试,您必须在 partsLineParts 分配之前设置样本种子 set.seed(###),以重新运行相同的随机数:

all.equal(DS, stationsList$DS)
# [1] TRUE
all.equal(D1, stationsList$D1)
# [1] TRUE
all.equal(D9, stationsList$D9)
# [1] TRUE

all.equal(stations_veclist, otherstations_veclist)
# [1] TRUE

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-15
    • 2014-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-03
    相关资源
    最近更新 更多