silent recycling in logical indexing

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

silent recycling in logical indexing

bbolker

  Sorry if this has been covered here somewhere in the past, but ...

  Does anyone know why logical vectors are *silently* recycled, even
when they are incommensurate lengths, when doing logical indexing?  This
is as documented:

  For ‘[’-indexing only: ‘i’, ‘j’, ‘...’ can be logical
          vectors, indicating elements/slices to select.  Such vectors
          are recycled if necessary to match the corresponding extent.

but IMO weird:

> x <- c(TRUE,TRUE,FALSE)
> y <- c(TRUE,FALSE)
> x[y]
[1]  TRUE FALSE

## (TRUE, FALSE) gets recycled to (TRUE,FALSE,TRUE) and selects
##  the first and third elements

If we do logical operations instead we do get a warning:

> x | y
[1] TRUE TRUE TRUE
Warning message:
In x | y : longer object length is not a multiple of shorter object length

  Is it just too expensive to test for incomplete recycling when doing
subsetting, or is there a sensible use case for incomplete recycling?

  Ll. 546ff of main/src/subscript.c suggest that there is a place in the
code where we already know if incomplete recycling has happened ...

 Thoughts?

   cheers
     Ben Bolker

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: silent recycling in logical indexing

R devel mailing list
One use case is when you want to extract every third item, starting with
the second, of an arbitrary vector with
    x[c(FALSE, TRUE, FALSE)]
instead of
    x[seq_along(x) %% 3 == 2]

Bill Dunlap
TIBCO Software
wdunlap tibco.com

On Thu, Jan 4, 2018 at 11:56 AM, Ben Bolker <[hidden email]> wrote:

>
>   Sorry if this has been covered here somewhere in the past, but ...
>
>   Does anyone know why logical vectors are *silently* recycled, even
> when they are incommensurate lengths, when doing logical indexing?  This
> is as documented:
>
>   For ‘[’-indexing only: ‘i’, ‘j’, ‘...’ can be logical
>           vectors, indicating elements/slices to select.  Such vectors
>           are recycled if necessary to match the corresponding extent.
>
> but IMO weird:
>
> > x <- c(TRUE,TRUE,FALSE)
> > y <- c(TRUE,FALSE)
> > x[y]
> [1]  TRUE FALSE
>
> ## (TRUE, FALSE) gets recycled to (TRUE,FALSE,TRUE) and selects
> ##  the first and third elements
>
> If we do logical operations instead we do get a warning:
>
> > x | y
> [1] TRUE TRUE TRUE
> Warning message:
> In x | y : longer object length is not a multiple of shorter object length
>
>   Is it just too expensive to test for incomplete recycling when doing
> subsetting, or is there a sensible use case for incomplete recycling?
>
>   Ll. 546ff of main/src/subscript.c suggest that there is a place in the
> code where we already know if incomplete recycling has happened ...
>
>  Thoughts?
>
>    cheers
>      Ben Bolker
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: silent recycling in logical indexing

Berry, Charles
In reply to this post by bbolker


> On Jan 4, 2018, at 11:56 AM, Ben Bolker <[hidden email]> wrote:
>
>
>  Sorry if this has been covered here somewhere in the past, but ...
>
>  Does anyone know why logical vectors are *silently* recycled, even
> when they are incommensurate lengths, when doing logical indexing?

It is convenient to use a single `TRUE' in programmatic manipulation of subscripts in the same manner as using an empty subscript interactively:

> mat<-diag(1:3)
> expr1 <- quote(mat[])
> expr1[[3]] <- TRUE
> expr1[[4]] <- 2
> eval(expr1)
[1] 0 2 0
> mat[,2]
[1] 0 2 0

HTH,

Chuck
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: silent recycling in logical indexing

bbolker
Hmm.

Chuck: I don't see how this example represents
incomplete/incommensurate recycling. Doesn't TRUE replicate from
length-1 to length-3 in this case (mat[c(TRUE,FALSE),2] would be an
example of incomplete recycling)?

William: clever, but maybe too clever unless you really need the
speed? (The clever way is 8 times faster in the following case ...)

x <- rep(1,1e6)
rbenchmark::benchmark(x[c(FALSE,TRUE,FALSE)],x[seq_along(x) %% 3 == 2])

On the other hand, it takes 0.025 vs 0.003 seconds per iteration ...
fortunes::fortune("7ms")


On Thu, Jan 4, 2018 at 4:09 PM, Berry, Charles <[hidden email]> wrote:

>
>
>> On Jan 4, 2018, at 11:56 AM, Ben Bolker <[hidden email]> wrote:
>>
>>
>>  Sorry if this has been covered here somewhere in the past, but ...
>>
>>  Does anyone know why logical vectors are *silently* recycled, even
>> when they are incommensurate lengths, when doing logical indexing?
>
> It is convenient to use a single `TRUE' in programmatic manipulation of subscripts in the same manner as using an empty subscript interactively:
>
>> mat<-diag(1:3)
>> expr1 <- quote(mat[])
>> expr1[[3]] <- TRUE
>> expr1[[4]] <- 2
>> eval(expr1)
> [1] 0 2 0
>> mat[,2]
> [1] 0 2 0
>
> HTH,
>
> Chuck

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: silent recycling in logical indexing

bbolker
PS I'm tempted to insert a warning at this point and see how often it
actually gets triggered ...

On Thu, Jan 4, 2018 at 4:44 PM, Ben Bolker <[hidden email]> wrote:

> Hmm.
>
> Chuck: I don't see how this example represents
> incomplete/incommensurate recycling. Doesn't TRUE replicate from
> length-1 to length-3 in this case (mat[c(TRUE,FALSE),2] would be an
> example of incomplete recycling)?
>
> William: clever, but maybe too clever unless you really need the
> speed? (The clever way is 8 times faster in the following case ...)
>
> x <- rep(1,1e6)
> rbenchmark::benchmark(x[c(FALSE,TRUE,FALSE)],x[seq_along(x) %% 3 == 2])
>
> On the other hand, it takes 0.025 vs 0.003 seconds per iteration ...
> fortunes::fortune("7ms")
>
>
> On Thu, Jan 4, 2018 at 4:09 PM, Berry, Charles <[hidden email]> wrote:
>>
>>
>>> On Jan 4, 2018, at 11:56 AM, Ben Bolker <[hidden email]> wrote:
>>>
>>>
>>>  Sorry if this has been covered here somewhere in the past, but ...
>>>
>>>  Does anyone know why logical vectors are *silently* recycled, even
>>> when they are incommensurate lengths, when doing logical indexing?
>>
>> It is convenient to use a single `TRUE' in programmatic manipulation of subscripts in the same manner as using an empty subscript interactively:
>>
>>> mat<-diag(1:3)
>>> expr1 <- quote(mat[])
>>> expr1[[3]] <- TRUE
>>> expr1[[4]] <- 2
>>> eval(expr1)
>> [1] 0 2 0
>>> mat[,2]
>> [1] 0 2 0
>>
>> HTH,
>>
>> Chuck

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: silent recycling in logical indexing

Berry, Charles
In reply to this post by bbolker


> On Jan 4, 2018, at 1:44 PM, Ben Bolker <[hidden email]> wrote:
>
> Chuck: I don't see how this example represents
> incomplete/incommensurate recycling.


It doesn't. I took your subject line to be the theme of your posting and `incommensurate lengths' to be an instance used to emphasize how silent recycling might `bite' the user.

Chuck
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: silent recycling in logical indexing

R devel mailing list
In reply to this post by bbolker
I have never used this construct.  However, part of my job is seeing how
well CRAN packages work in our reimplementation of the R language
and I am continually surprised by the inventiveness of package writers.

Bill Dunlap
TIBCO Software
wdunlap tibco.com

On Thu, Jan 4, 2018 at 1:44 PM, Ben Bolker <[hidden email]> wrote:

> Hmm.
>
> Chuck: I don't see how this example represents
> incomplete/incommensurate recycling. Doesn't TRUE replicate from
> length-1 to length-3 in this case (mat[c(TRUE,FALSE),2] would be an
> example of incomplete recycling)?
>
> William: clever, but maybe too clever unless you really need the
> speed? (The clever way is 8 times faster in the following case ...)
>
> x <- rep(1,1e6)
> rbenchmark::benchmark(x[c(FALSE,TRUE,FALSE)],x[seq_along(x) %% 3 == 2])
>
> On the other hand, it takes 0.025 vs 0.003 seconds per iteration ...
> fortunes::fortune("7ms")
>
>
> On Thu, Jan 4, 2018 at 4:09 PM, Berry, Charles <[hidden email]> wrote:
> >
> >
> >> On Jan 4, 2018, at 11:56 AM, Ben Bolker <[hidden email]> wrote:
> >>
> >>
> >>  Sorry if this has been covered here somewhere in the past, but ...
> >>
> >>  Does anyone know why logical vectors are *silently* recycled, even
> >> when they are incommensurate lengths, when doing logical indexing?
> >
> > It is convenient to use a single `TRUE' in programmatic manipulation of
> subscripts in the same manner as using an empty subscript interactively:
> >
> >> mat<-diag(1:3)
> >> expr1 <- quote(mat[])
> >> expr1[[3]] <- TRUE
> >> expr1[[4]] <- 2
> >> eval(expr1)
> > [1] 0 2 0
> >> mat[,2]
> > [1] 0 2 0
> >
> > HTH,
> >
> > Chuck
>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel