編輯:我應該使用更大的數據集的基準,小數據集使基準測試結果有點誤導。請參閱PatrickRoocks的更新。
我剛剛評論說,for循環不一定比應用家庭差,然後我看到了這一點。
我做了一個比較優化的for循環和sapply方法的microbenchmark。 for循環速度快6倍。 sapply方法不是一個適當的函數,將它修改爲一個採用向量的函數,而不是假設數據幀列可以稍微改進一點。
df <- data.frame(X = c(5000, 6000, 5500, 5000, 5300))
count_above <- function(v)
{
counts <- integer(length = length(v))
counts[1] <- 0
for (i in 2:length(v))
{
counts[i] <- sum(v[1:(i-1)] < v[i])
}
return(counts)
}
count_above(df$X)
microbenchmark::microbenchmark(count_above(df$X), sapply(seq_len(nrow(df)), function(i) sum(df[i:1, c("X")] < df$X[i])), times = 10)
Unit: microseconds
expr
count_above(df$X)
sapply(seq_len(nrow(df)), function(i) sum(df[i:1, c("X")] < df$X[i]))
min lq mean median uq max neval cld
38.623 41.068 65.0722 55.0010 65.512 142.757 10 a
262.045 269.379 368.6231 339.2905 415.067 640.934 10 b
更新:
# modify Parfait's answer into a function, taking vector instead of data frame
count_above_2 <- function(v){
counts <- sapply(seq_len(length(v)),
function(i) sum(v[i:1] < v[i]))
return(counts)
}
X <- df$X
microbenchmark::microbenchmark(count_above(X), count_above_2(X), {indices <- 1:length(X); colSums(outer(X, X, "<") & outer(indices, indices, "<"))}, times = 100)
Unit: microseconds
expr
count_above(X)
count_above_2(X)
{ indices <- 1:length(X) colSums(outer(X, X, "<") & outer(indices, indices, "<")) }
min lq mean median uq max neval cld
21.023 23.4680 39.02878 26.1565 35.4450 144.224 100 a
41.067 49.3785 67.06162 53.2900 70.1565 166.712 100 b
37.646 40.0900 66.45059 53.0450 72.8455 258.623 100 b
For循環仍然獲勝。 傳遞一個矢量而不是所有的節省時間,所以我給3個解決方案相同的向量是可比較的。 Parfait的答案與PatrickRoocks的答案相當。
除了表現,還有一個微妙的正確點。
因爲v [i] < v [i]是FALSE,所以OP的函數和Parfait的和(v [i:1] < v [i])給出正確的答案。根據定義,它應該使用v [1:(i-1)] < v [i]。
我的功能可以寫在一個更簡潔的版本是這樣的:
count_above <- function(v)
{
counts <- integer(length = length(v))
for (i in 1:length(v))
{
counts[i] <- sum(v[1:(i-1)] < v[i])
}
return(counts)
}
它看起來更好,並給予正確的結果。這也取決於v [1] < v [1]是否爲FALSE。這不一定是錯誤的,因爲它只是第一行,儘管我仍然更喜歡更長,但更明顯的版本。
通常,您希望避免for循環並使用矢量化函數。但是在這種情況下,對於每一行,您需要比較i-1值,而且我不認爲這可以向量化很多。有時只是保持循環是可以的。用適用的家庭包裝它可能會傷害到可讀性。 – dracodoc
儘管可以改進函數中的幾個點:1.創建具有固定大小的計數向量,而不是在每一步中增加計數向量。 2.不需要創建temp,只需使用vector [1:i]就可以了。 3.不要使用保留名稱作爲變量,如參數'vector'。 4.它應該是向量[1:(i-1)] – dracodoc