wiem, że to nie ma rzeczywiście odpowiedzieć główną myśl pytanie (@hadley zrobiła i że zasługuje na kredyt), ale istnieją inne opcje dla tych, sugerujesz. Tutaj możesz użyć pmin()
i pmax()
jako innego rozwiązania, a używając with()
lub within()
możemy to zrobić bez wyraźnego podzbioru, aby utworzyć dd
.
R> set.seed(1)
R> dat <- data.frame(depth1 = runif(10), depth2 = runif(10))
R> dat <- within(dat, mindepth <- pmin(depth1, depth2))
R> dat <- within(dat, maxdepth <- pmax(depth1, depth2))
R>
R> dat
depth1 depth2 mindepth maxdepth
1 0.26550866 0.2059746 0.20597457 0.2655087
2 0.37212390 0.1765568 0.17655675 0.3721239
3 0.57285336 0.6870228 0.57285336 0.6870228
4 0.90820779 0.3841037 0.38410372 0.9082078
5 0.20168193 0.7698414 0.20168193 0.7698414
6 0.89838968 0.4976992 0.49769924 0.8983897
7 0.94467527 0.7176185 0.71761851 0.9446753
8 0.66079779 0.9919061 0.66079779 0.9919061
9 0.62911404 0.3800352 0.38003518 0.6291140
10 0.06178627 0.7774452 0.06178627 0.7774452
Możemy spojrzeć na ile kopiowanie idzie z tracemem()
ale tylko jeśli R został skompilowany z następującą opcję konfiguracji aktywowane --enable-memory-profiling
.
R> set.seed(1)
R> dat <- data.frame(depth1 = runif(10), depth2 = runif(10))
R> tracemem(dat)
[1] "<0x2641cd8>"
R> dat <- within(dat, mindepth <- pmin(depth1, depth2))
tracemem[0x2641cd8 -> 0x2641a00]: within.data.frame within
tracemem[0x2641a00 -> 0x2641878]: [<-.data.frame [<- within.data.frame within
R> tracemem(dat)
[1] "<0x2657bc8>"
R> dat <- within(dat, maxdepth <- pmax(depth1, depth2))
tracemem[0x2657bc8 -> 0x2c765d8]: within.data.frame within
tracemem[0x2c765d8 -> 0x2c764b8]: [<-.data.frame [<- within.data.frame within
Widzimy więc, że R kopiowane dat
dwukrotnie podczas każdego within()
rozmowy. Porównaj to z twoich dwóch sugestie:
R> set.seed(1)
R> dat <- data.frame(depth1 = runif(10), depth2 = runif(10))
R> tracemem(dat)
[1] "<0x2e1ddd0>"
R> dd <- dat[,c("depth1","depth2")]
R> tracemem(dd)
[1] "<0x2df01a0>"
R> dat$mindepth = apply(dd,1,min)
tracemem[0x2df01a0 -> 0x2cf97d8]: as.matrix.data.frame as.matrix apply
tracemem[0x2e1ddd0 -> 0x2cc0ab0]:
tracemem[0x2cc0ab0 -> 0x2cc0b20]: $<-.data.frame $<-
tracemem[0x2cc0b20 -> 0x2cc0bc8]: $<-.data.frame $<-
R> tracemem(dat)
[1] "<0x26b93c8>"
R> dat$maxdepth = apply(dd,1,max)
tracemem[0x2df01a0 -> 0x2cc0e30]: as.matrix.data.frame as.matrix apply
tracemem[0x26b93c8 -> 0x26742c8]:
tracemem[0x26742c8 -> 0x2674358]: $<-.data.frame $<-
tracemem[0x2674358 -> 0x2674478]: $<-.data.frame $<-
Tutaj dd
są kopiowane raz w każdym wywołaniu apply
ponieważ apply()
konwertuje dd
do matrycy przed kontynuowaniem. Ostatnie trzy linie w każdym bloku wyjściowym tracemem
wskazują, że trzy kopie dat
są tworzone w celu wstawienia nowej kolumny.
Co z drugą opcją?
R> set.seed(1)
R> dat <- data.frame(depth1 = runif(10), depth2 = runif(10))
R> tracemem(dat)
[1] "<0x268bc88>"
R> dat$mindepth <- apply(dat[,c("depth1","depth2")],1,min)
tracemem[0x268bc88 -> 0x26376b0]:
tracemem[0x26376b0 -> 0x2637720]: $<-.data.frame $<-
tracemem[0x2637720 -> 0x2637790]: $<-.data.frame $<-
R> tracemem(dat)
[1] "<0x2466d40>"
R> dat$maxdepth <- apply(dat[,c("depth1","depth2")],1,max)
tracemem[0x2466d40 -> 0x22ae0d8]:
tracemem[0x22ae0d8 -> 0x22ae1f8]: $<-.data.frame $<-
tracemem[0x22ae1f8 -> 0x22ae318]: $<-.data.frame $<-
Tutaj ta wersja unika kopię udział w tworzeniu dd
, ale we wszystkich innych aspektach jest podobny do poprzedniego sugestię.
Czy możemy zrobić coś lepszego? Tak, i jeden prosty sposób to użycie opcji within()
Zacząłem jednak wykonać oba oświadczenia do tworzenia nowych mindepth
i maxdepth
zmienne w jednym wywołaniu within()
:
R> set.seed(1)
R> dat <- data.frame(depth1 = runif(10), depth2 = runif(10))
R> tracemem(dat)
[1] "<0x21c4158>"
R> dat <- within(dat, { mindepth <- pmin(depth1, depth2)
+ maxdepth <- pmax(depth1, depth2) })
tracemem[0x21c4158 -> 0x21c44a0]: within.data.frame within
tracemem[0x21c44a0 -> 0x21c4628]: [<-.data.frame [<- within.data.frame within
W tej wersji mamy tylko powołać dwie kopie dat
w porównaniu z 4 kopiami oryginalnej wersji within()
.
Co powiesz, jeśli zmusimy dat
do matrycy, a następnie wykonamy wstawienia?
R> set.seed(1)
R> dat <- data.frame(depth1 = runif(10), depth2 = runif(10))
R> tracemem(dat)
[1] "<0x1f29c70>"
R> mat <- as.matrix.data.frame(dat)
tracemem[0x1f29c70 -> 0x1f09768]: as.matrix.data.frame
R> tracemem(mat)
[1] "<0x245ff30>"
R> mat <- cbind(mat, pmin(mat[,1], mat[,2]), pmax(mat[,1], mat[,2]))
R>
To jest poprawa jak tylko ponieść koszt pojedynczej kopii dat
gdy zmuszanie do matrycy.Oszukałem trochę, dzwoniąc bezpośrednio do metody as.matrix.data.frame()
. Gdybyśmy po prostu używali as.matrix()
, ponosilibyśmy inną kopię mat
.
Podkreśla to jeden z powodów, dla których macierze są znacznie szybsze w użyciu niż ramki danych.
Poddanie prawie wszystkiego w R tworzy kopię. Istnieje kilka wyjątków w przesyłanych pakietach. – hadley
@hadley - czy chcesz opublikować to jako odpowiedź, aby można było zaakceptować itp. Tylko dla rekordów ...? –