Каква е разликата между with и within в R?

Винаги използвам с вместо в контекста на моето изследване, но първоначално мислех, че са еднакви. Току що въвеждам грешка с for within и върнатите резултати са доста различни. Чудя се защо?

Използвам бейзболните данни в пакета plyr, така че първо зареждам библиотеката от

 require(plyr)

След това искам да избера всички редове с идентификатор ansonca01. Отначало, както казах, използвах в и стартирах функцията, както следва:

within(baseball, baseball[id=="ansonca01", ])

Получих много странни резултати, които основно включват всичко:

       id year stint team lg   g  ab   r   h X2b X3b hr rbi  sb cs  bb  so ibb hbp sh sf gidp
4     ansonca01 1871     1  RC1     25 120  29  39  11   3  0  16   6  2   2   1  NA  NA NA NA   NA
44    forceda01 1871     1  WS3     32 162  45  45   9   4  0  29   8  0   4   0  NA  NA NA NA   NA
68    mathebo01 1871     1  FW1     19  89  15  24   3   1  0  10   2  1   2   0  NA  NA NA NA   NA
99    startjo01 1871     1  NY2     33 161  35  58   5   1  1  34   4  2   3   0  NA  NA NA NA   NA
102   suttoez01 1871     1  CL1     29 128  35  45   3   7  3  23   3  1   1   0  NA  NA NA NA   NA
106   whitede01 1871     1  CL1     29 146  40  47   6   5  1  21   2  2   4   1  NA  NA NA NA   NA
113    yorkto01 1871     1  TRO     29 145  36  37   5   7  2  23   2  2   9   1  NA  NA NA NA   NA
.........

Тогава използвам с вместо в,

 with(baseball, baseball[id=="ansonca01",])

и получих резултатите, които очаквах

      id year stint team lg   g  ab   r   h X2b X3b hr rbi sb cs  bb so ibb hbp sh sf gidp
4    ansonca01 1871     1  RC1     25 120  29  39  11   3  0  16  6  2   2  1  NA  NA NA NA   NA
121  ansonca01 1872     1  PH1     46 217  60  90  10   7  0  50  6  6  16  3  NA  NA NA NA   NA
276  ansonca01 1873     1  PH1     52 254  53 101   9   2  0  36  0  2   5  1  NA  NA NA NA   NA
398  ansonca01 1874     1  PH1     55 259  51  87   8   3  0  37  6  0   4  1  NA  NA NA NA   NA
525  ansonca01 1875     1  PH1     69 326  84 106  15   3  0  58 11  6   4  2  NA  NA NA NA   NA

Проверих документацията на с и в рамките, като написах help(with) в R среда и получих следното:

with е обща функция, която оценява expr в локална среда, конструирана от данни. Средата има средата на повикващия като родител. Това е полезно за опростяване на извикванията на функции за моделиране. (Забележка: ако данните вече са среда, това се използва със съществуващия родител.)

Обърнете внимание, че присвояванията в рамките на expr се извършват в изградената среда, а не в работното пространство на потребителя.

в рамките е подобно, с изключение на това, че изследва средата след оценката на expr и прави съответните модификации на данните (това може да се провали в случай на рамка с данни, ако са създадени обекти, които не могат да бъдат съхранени в рамка с данни), и го връща. в рамките на може да се използва като алтернатива на трансформация.

От това обяснение на разликите не разбирам защо получих различни резултати с толкова проста операция. Някой има ли идеи?


person nan    schedule 17.02.2014    source източник
comment
Защо изобщо използвате with в израз като: with(baseball,baseball[id=="ansonca01",])? Трябва ви само baseball[baseball$id=="ansonca01",].   -  person Thomas    schedule 17.02.2014
comment
within връща пълната рамка с данни. Правенето на извличане вътре в within всъщност няма никакъв смисъл. Опитайте да създадете нова променлива вътре в with и вътре в within и ще видите разликата по-ясно.   -  person Thomas    schedule 17.02.2014
comment
@Thomas Здравейте, разбира се, че знам, че мога да направя подмножеството с бейзбол[baseball$id==ansonca01,] и всъщност винаги съм го правил по този начин. Днес просто исках да опитам нещо различно и намерих с и в рамките на връщане различни резултати за такава проста операция. Искам да разбера защо!!! Научих, че Within е за създаване на нови променливи, но това не отговаря на моя въпрос, публикуван тук, поради което тези две функции водят до различни резултати в случая на подмножество?   -  person nan    schedule 17.02.2014
comment
@Thomas Работата е там, че в този пример посочих само едно условие за подмножество, което е [id==ansonca01]. Ако искам да посоча повече условия за различни колони, тогава трябва да напиша baseball$somevariable много пъти или да направя прикачване/отделяне, with/within може би е добре за спестяване на усилия.   -  person nan    schedule 17.02.2014
comment
тъй като зареждате plyr, можете също да опитате summarise и mutate.   -  person baptiste    schedule 17.02.2014
comment
... и още по-добре, техните dplyr братовчеди.   -  person baptiste    schedule 17.02.2014
comment
всъщност първата част от въпроса, която искам да избера всички редове... извиква subset(baseball, id=="ansonca01")   -  person baptiste    schedule 17.02.2014


Отговори (3)


документацията е доста ясна за семантика и връщани стойности (и добре съвпада с ежедневните значения на думите „с“ и „в“):

Стойност:

За „with“, стойността на оцененото „expr“. За „within“, модифицираният обект.

Тъй като вашият код не променя нищо вътре в baseball, немодифицираният baseball се връща. with от друга страна не връща обекта, връща expr.

Ето пример, в който expression модифицира обекта:

> head(within(cars, speed[dist < 20] <- 1))
  speed dist
1     1    2
2     1   10
3     1    4
4     7   22
5     1   16
6     1   10
person Konrad Rudolph    schedule 17.02.2014
comment
Мисля, че това е отговорът на въпроса ми. Всъщност прочетох цитираното от вас съдържание от документацията, но не разбрах напълно това изречение (за „with“, стойността на оценения „expr“. За „within“, модифицираният обект), когато го прочетох. Вашето обяснение ми помага да го преосмисля и има смисъл. Сега разбирам, че with връща резултата за израза. За вътре, ако не модифицирате нищо, тогава се връща оригиналният обект. Благодаря! - person nan; 17.02.2014
comment
можете ли да кажете как r тества дали обектът е модифициран в случай на within, като проверява наличието на <-? - person SIslam; 23.03.2017
comment
@SIslam Това не проверява. Той просто оценява израза, който предавате през within, и извършва оценката вътре в рамката с данни. - person Konrad Rudolph; 23.03.2017

Смятам, че прости примери често работят, за да подчертаят разликата. Нещо като:

df <- data.frame(a=1:5,b=2:6)
df
  a b
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6

with(df, {c <- a + b; df;} )
  a b
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6

within(df, {c <- a + b; df;} )
# equivalent to: within(df, c <- a + b)
# i've just made the return of df explicit 
# for comparison's sake
  a b  c
1 1 2  3
2 2 3  5
3 3 4  7
4 4 5  9
5 5 6 11
person thelatemail    schedule 17.02.2014

Както по-горе, with връща стойността на последния оценен израз. Удобен е за едноредови като:

with(cars, summary(lm (speed ~ dist)))

но не е подходящ за изпращане на множество изрази.

Често намирам within за полезен за манипулиране на data.frame или list (или data.table), тъй като намирам синтаксиса за лесен за четене.

Смятам, че документацията може да бъде подобрена чрез добавяне на примери за употреба в това отношение, напр.:

df1 <- data.frame(a=1:3,
              b=4:6,
              c=letters[1:3])
## library("data.table")  
## df1 <- as.data.table(df1)
df1 <- within(df1, {
    a <- 10:12
    b[1:2] <- letters[25:26]
    c <- a
})
df1

даване

    a b  c
1: 10 y 10
2: 11 z 11
3: 12 6 12

и

df1 <- as.list(df1)
df1 <- within(df1, {
    a <- 20:23
    b[1:2] <- letters[25:26]
    c <- paste0(a, b)
})
df1

даване

$a
[1] 20 21 22 23

$b
[1] "y" "z" "6"

$c
[1] "20y" "21z" "226" "23y"

Обърнете внимание също, че methods("within") дава само тези типове обекти, които са:

  • within.data.frame
  • within.list
  • within.data.table, ако пакетът е зареден).

Други пакети могат да дефинират допълнителни методи.

Може би неочаквано за някои, with и within обикновено не са подходящи избори при манипулиране на променливи в рамките на дефинирани среди...

За адрес на коментара - няма within.environment метод. Използването на with изисква да имате функцията, която извиквате в средата, което донякъде проваля целта за мен, напр.

df1 <- as.environment(df1)
## with(df1, ls()) ## Error
assign("ls", ls, envir=df1)
with(df1, ls())
person dardisco    schedule 16.09.2018
comment
можеш ли да обясниш малко повече последното си изречение? - person Ben Bolker; 16.09.2018