From m@ech|er @end|ng |rom @t@t@m@th@ethz@ch  Thu Dec  9 17:35:33 2021
From: m@ech|er @end|ng |rom @t@t@m@th@ethz@ch (Martin Maechler)
Date: Thu, 9 Dec 2021 17:35:33 +0100
Subject: [Rd] plogis (and other p* functions), vectorized lower.tail
In-Reply-To: <a8c1428c-e7a5-d5c9-a437-efe448aef2ae@insa-toulouse.fr>
References: <1MCKBm-1mmk5c180A-009QA7@mail.gmx.net>
 <25010.6851.980357.14339@stat.math.ethz.ch>
 <0bd8b088-40c6-f62d-a296-9b540c1c1e55@gmail.com>
 <a8c1428c-e7a5-d5c9-a437-efe448aef2ae@insa-toulouse.fr>
Message-ID: <25010.12373.335441.351617@stat.math.ethz.ch>

>>>>> Sokol Serguei on Thu, 9 Dec 2021 17:13:36 +0100 writes:

    > On 09/12/2021 16:55, Ben Bolker wrote:
    >> 
    >> 
    >> On 12/9/21 10:03 AM, Martin Maechler wrote:
    >>>>>>>> Matthias Gondan
    >>>>>>>> ???? on Wed, 8 Dec 2021 19:37:09 +0100 writes:
    >>> 
    >>> ???? > Dear R developers,
    >>> ???? > I have seen that plogis silently ignores vector elements of 
    >>> lower.tail,
    >>> 
    >>> and also of 'log'.
    >>> This is indeed the case for all d*, p*, q* functions.
    >>> 
    >>> Yes, this has been on purpose and therefore documented, in the
    >>> case of plogis, e.g. in the 'Value' section of ?plogis :
    >>> 
    >>> ????? The length of the result is determined by ?n? for ?rlogis?, and is
    >>> ????? the maximum of the lengths of the numerical arguments for the
    >>> ????? other functions.
    >>> 
    >>> ? (note: *numerical* arguments: the logical ones are not recycled)
    >>> 
    >>> ????? The numerical arguments other than ?n? are recycled to the length
    >>> ????? of the result.? Only the first elements of the logical arguments
    >>> ????? are used.
    >>> 
    >>> ? (above, we even explicitly mention the logical arguments ..)
    >>> 
    >>> 
    >>> Recycling happens for the first argument (x,p,q) of these
    >>> functions and for "parameters" of the distribution, but not for
    >>> lower.tail, log.p (or 'log').
    >>> 
    >>> 
    >>> ???? >> plogis(q=0.5, location=1, lower.tail=TRUE)
    >>> ???? > [1] 0.3775407
    >>> ???? >> plogis(q=0.5, location=1, lower.tail=FALSE)
    >>> ???? > [1] 0.6224593
    >>> ???? >> plogis(q=c(0.5, 0.5), location=1, lower.tail=c(TRUE, FALSE))
    >>> ???? > [1] 0.3775407 0.3775407
    >>> 
    >>> ???? > For those familiar with psychological measurement: A use case 
    >>> of the above function is the so-called Rasch model, where the 
    >>> probability that a person with some specific ability (q) makes a 
    >>> correct (lower.tail=TRUE) or wrong response (lower.tail=FALSE) to an 
    >>> item with a specific difficulty (location). A vectorized version of 
    >>> plogis would enable to determine the likelihood of an entire response 
    >>> vector in a single call. My current workaround is an intermediate 
    >>> call to ?Vectorize?.
    >>> 
    >>> ???? > I am wondering if the logical argument of lower.tail can be 
    >>> vectorized (?). I see that this may be a substantial change in many 
    >>> places (basically, all p and q functions of probability 
    >>> distributions), but in my understanding, it would not break existing 
    >>> code which assumes lower.tail to be a single element. If that?s not
    >>> ???? > possible/feasible, I suggest to issue a warning if a vector of 
    >>> length > 1 is given in lower.tail. I am aware that the documentation 
    >>> clearly states that lower.tail is a single boolean.
    >>> 
    >>> aah ok, here you say you know that the current behavior is documented.
    >>> 
    >>> ???? > Thank you for your consideration.
    >>> 
    >>> 
    >>> As you mention, changing this would be quite a large endeavor.
    >>> I had thought about doing that many years ago, not remembering
    >>> details, but seeing that in almost all situations you really
    >>> only need one of the two tails? (for Gaussian- or t- based confidence
    >>> intervals you also only need one, for symmetry reason).
    >>> 
    >>> Allowing the recycling there would make the intermediate C code
    >>> (which does the recycling) larger and probably slightly
    >>> slower because of conceptually two more for loops which would in
    >>> 99.9% only have one case ..
    >>> 
    >>> I'd have found that ugly to add. ... ...
    >>> ... but of course, if you can prove that the code bloat would not be 
    >>> large
    >>> and not deteriorate speed in a measurable way and if you'd find
    >>> someone to produce a comprehensive and tested patch ...
    >>> 
    >>> Martin
    >>> 
    >>> 
    >>> ???? > With best wishes,
    >>> ???? > Matthias
    >>> 
    >>> 
    >>> 
    >>> ???? > [[alternative HTML version deleted]]
    >>> 
    >>> ???? > ______________________________________________
    >>> ???? > R-devel at r-project.org mailing list
    >>> ???? > https://stat.ethz.ch/mailman/listinfo/r-devel
    >>> 
    >>> ______________________________________________
    >>> R-devel at r-project.org mailing list
    >>> https://stat.ethz.ch/mailman/listinfo/r-devel
    >>> 
    >> 
    >> ? I agree with everything said above, but think that adding a warning 
    >> when length(lower.tail) > 1 (rather than silently ignoring) might be 
    >> helpful ...? ??
    >> 
    >> ? As for the vectorization, it seems almost trivial to do at the user 
    >> level when needed (albeit it's probably a little bit inefficient):
    >> 
    >> pv <- Vectorize(plogis, c("q", "location", "scale", "lower.tail"))
    >> pv(q=c(0.5, 0.5), location=1, lower.tail=c(TRUE, FALSE))
    >> [1] 0.3775407 0.6224593

    > .. or directly use mapply()

    > mapply(plogis, q=c(0.5, 0.5), location=1, lower.tail=c(TRUE, FALSE))
    > [1] 0.3775407 0.6224593

Very nice, yes.  Also, there's no need to recycle/vectorize yourself:
 q=0.5  is sufficient:

 > mapply(plogis, q=0.5, location=1, lower.tail=c(TRUE, FALSE))
 [1] 0.3775407 0.6224593


Martin



[Rd] plogis (and other p* functions), vectorized lower.tail
Martin Maechler