Her satırın önceki 2 sayısını toplamak için sütunları yineleyin
R'de, 'A', 'B', 'C', 'D' sütunlarına sahip bir veri çerçevem var. Sütunların 100 satırı vardır.
Veri çerçevesindeki tüm satırlar için o sütunun önceki 2 satırını toplayan bir hesaplama yapmak ve ardından yeni sütunlarda ('AA', 'AB', vb.) Bu toplamın ne olduğunu ayarlamak için sütunları yinelemem gerekiyor:
A B C D
1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7
5 6 7 8
6 7 8 9
-e
A B C D AA AB AC AD
1 2 3 4 NA NA NA NA
2 3 4 5 3 5 7 9
3 4 5 6 5 7 9 11
4 5 6 7 7 9 11 13
5 6 7 8 9 11 13 15
6 7 8 9 11 13 15 17
Yinelemek istediğim sütunları (seçilen sütunlar, tüm sütunlar değil) ve ayarlamak istediğim sütunları ayarlamama izin veren bir işlevi / döngüyü nasıl oluşturacağımı birisi açıklayabilir mi?
Yanıtlar
Bir base
tek astar:
cbind(df, setNames(df + df[c(NA, 1:(nrow(df)-1)), ], paste0("A", names(df))))
Verileriniz büyükse, bu en hızlı olabilir çünkü tamamını işliyor data.frame
.
Bir dplyr
kullanılarak çözelti mutate()
ile across()
.
library(dplyr)
df %>%
mutate(across(A:D,
~ .x + lag(.x),
.names = "A{col}"))
# A B C D AA AB AC AD
# 1 1 2 3 4 NA NA NA NA
# 2 2 3 4 5 3 5 7 9
# 3 3 4 5 6 5 7 9 11
# 4 4 5 6 7 7 9 11 13
# 5 5 6 7 8 9 11 13 15
# 6 6 7 8 9 11 13 15 17
Önceki 3 satırı toplamak istiyorsanız, ikinci argüman across()
, ie .fns
, olmalıdır
~ .x + lag(.x) + lag(.x, 2)
ki kullanımına eşdeğerdir rollsum()
içinde zoo
:
~ zoo::rollsum(.x, k = 3, fill = NA, align = 'right')
Kıyaslama
10000 satır ve 100 sütunlu microbenchmark
yeni bir paket ile bir kıyaslama testi data.frame
ve her bir ifadeyi 10 kez değerlendirin.
# Unit: milliseconds
# expr min lq mean median uq max neval
# darren_base 18.58418 20.88498 35.51341 33.64953 39.31909 80.24725 10
# darren_dplyr_lag 39.49278 40.27038 47.26449 42.89170 43.20267 76.72435 10
# arg0naut91_dplyr_rollsum 436.22503 482.03199 524.54800 516.81706 534.94317 677.64242 10
# Grothendieck_rollsumr 3423.92097 3611.01573 3650.16656 3622.50895 3689.26404 4060.98054 10
dplyr
'S' i kullanabilir across
(ve isteğe bağlı adları ayarlayabilirsiniz) hareketli toplamla (uygulandığı gibi zoo
):
library(dplyr)
library(zoo)
df %>%
mutate(
across(
A:D,
~ rollsum(., k = 2, fill = NA, align = 'right'),
.names = 'A{col}'
)
)
Çıktı:
A B C D AA AB AC AD
1 1 2 3 4 NA NA NA NA
2 2 3 4 5 3 5 7 9
3 3 4 5 6 5 7 9 11
4 4 5 6 7 7 9 11 13
5 5 6 7 8 9 11 13 15
6 6 7 8 9 11 13 15 17
İle A:D
işlevi uygulamak istediğimiz sütun adlarının aralığını belirledik. Yukarıdaki .names
argümandaki varsayım A
, önek ve sütun adını ( {col}
) birlikte yapıştırmak istediğinizdir .
İşte bir data.table çözümü. İstediğiniz gibi, yalnızca tüm sütunlar için değil, hangi sütunlara uygulamak istediğinizi seçmenize izin verir.
library(data.table)
x <- data.table(A=1:6, B=2:7, C=3:8, D=4:9)
selected_cols <- c('A','B','D')
new_cols <- paste0("A",selected_cols)
x[, (new_cols) := lapply(.SD, function(col) col+shift(col, 1)), .SDcols = selected_cols]
x[]
NB Bu, diğer en hızlı yanıttan 2 veya 3 kat daha hızlıdır.
Bu, iç içe geçmiş for
döngülerle saf bir yaklaşımdır . Yüz bin satırın üzerinde yineleme yapacaksanız çok yavaş olduğuna dikkat edin.
i <- 1
n <- 5
df <- data.frame(A=i:(i+n), B=(i+1):(i+n+1), C=(i+2):(i+n+2), D=(i+3):(i+n+3))
for (col in colnames(df)) {
for (ind in 1:nrow(df)) {
if (ind-1==0) {next}
s <- sum(df[c(ind-1, ind), col])
df[ind, paste0('S', col)] <- s
}
}
Bu bir cumsum
yöntemdir:
na.df <- data.frame(matrix(NA, 2, ncol(df)))
colnames(na.df) <- colnames(df)
cs1 <- cumsum(df)
cs2 <- rbind(cs1[-1:-2,], na.df)
sum.diff <- cs2-cs1
cbind(df, rbind(na.df[1,], cs1[2,], sum.diff[1:(nrow(sum.diff)-2),]))
Kıyaslama:
# Unit: milliseconds
# expr min lq mean median uq max neval
# darrentsai.rbind 11.5623 12.28025 23.38038 16.78240 20.83420 91.9135 100
# darrentsai.rbind.rev1 8.8267 9.10945 15.63652 9.54215 14.25090 62.6949 100
# pseudopsin.dt 7.2696 7.52080 20.26473 12.61465 17.61465 69.0110 100
# ivan866.cumsum 25.3706 30.98860 43.11623 33.78775 37.36950 91.6032 100
Cumsum yönteminin çoğu zaman df tahsislerinde boşa gittiğine inanıyorum. Data.table arka uca doğru şekilde uyarlanırsa, en hızlısı olabilir.
İstediğimiz sütunları belirtin. Bunu yapmanın birkaç farklı yolunu gösteriyoruz. Ardından rollsumr
, istenen sütunları elde etmek, sütun adlarını ayarlamak ve DF
onunla cbind yapmak için kullanın.
library(zoo)
# jx <- names(DF) # if all columns wanted
# jx <- sapply(DF, is.numeric) # if all numeric columns
# jx <- c("A", "B", "C", "D") # specify columns by name
jx <- 1:4 # specify columns by position
r <- rollsumr(DF[jx], 2, fill = NA)
colnames(r) <- paste0("A", colnames(r))
cbind(DF, r)
veren:
A B C D AA AB AC AD
1 1 2 3 4 NA NA NA NA
2 2 3 4 5 3 5 7 9
3 3 4 5 6 5 7 9 11
4 4 5 6 7 7 9 11 13
5 5 6 7 8 9 11 13 15
6 6 7 8 9 11 13 15 17
Not
Tekrarlanabilir formdaki girdi:
DF <- structure(list(A = 1:6, B = 2:7, C = 3:8, D = 4:9),
class = "data.frame", row.names = c(NA, -6L))