Interp {Ecfun} | R Documentation |
Interpolate between numbers or numbers of characters
Description
Numeric interpolation is defined in the usual way:
xOut <- x*(1-proportion) + y*proportion
Character interpolation does linear interpolation
on the number of characters of x
and
y
. If length(proportion) == 1
,
interpolation is done on cumsum(nchar(.))
.
If length(proportion) > 1
, interpolation
is based on nchar
. In either case,
the interpolant is rounded to an integer number
of characters. Interp
then returns
substring(y, ...)
unless nchar(x)
>
nchar(y)
, when it returns
substring(x, ...)
.
Character interpolation is used in two cases:
(1) At least one of x
and y
is
character.
(2) At least one of x
and y
is
neither logical, integer, numeric, complex nor
raw, and class(unclass(.))
is either
integer or character.
In all other cases, numeric interpolation is used.
NOTE: This seems to provide a relatively simple
default for what most people would want from
the six classes of atomic vectors (logical,
integer, numeric, complex, raw, and character)
and most other classes. For example,
class(unclass(factor))
is integer. The
second rule would apply to this converting it to
character. The coredata
of an
object of class zoo
could be
most anything, but this relatively simple rule
would deliver what most people want in most case.
An exception would be an object with integer
coredata
. To handle this as numeric, a
Interp.zoo
function would have to be
written.
Usage
Interp(x, ...)
## Default S3 method:
Interp(x, y, proportion,
argnames=character(3),
message0=character(0), ...)
InterpChkArgs(x, y, proportion,
argnames=character(3),
message0=character(0), ...)
InterpChar(argsChk, ...)
InterpNum(argsChk, ...)
Arguments
x , y |
two vectors of the same class or to be coerced to the same class. |
proportion |
A number or numeric vector assumed to be between 0 and 1. |
argnames |
a character vector of length 3 giving
arguments |
message0 |
A character string to be passed with
|
argsChk |
a list as returned by |
... |
optional arguments for
|
Details
Interp
is an S3 generic function to
allow users to easily modify the behavior
to interpolate between special classes of
objects.
Interp
has two basic algorithms for
"Numeric" and "Character" interpolation.
The computations begin by calling
InterpChkArgs
to dispose quickly of
simple cases (e.g, x
or y
missing
or length
0 or if proportion
is <= 0 or >= 1 or
missing
). It returns a list.
If the list contains a component named
xout
, Interp
returns that value
with no further computations.
Otherwise, the list returned by
InterpChkArgs
includes components
"algorithm", "x", "y", "proportion",
pLength1
(defined below), "raw", and
"outclass". The "algorithm" component must
be either "Numeric" or "Character". That
algorithm is then performed as discussed below
using arguments "x", "y", and "proportion";
all three will have the same length. The
class of "x" and "y" will match the algorithm.
The list component "raw" is logical:
TRUE
if the output will be raw or such
that class(unclass(.))
of the output will
be raw. In that case, a "Numeric" interpolation
will be transformed back into "raw". "outclass"
will either be a list of attributes to apply to
the output or NA. If a list, xout
will be
added as component ".Data" to the list "outclass"
and then then processed as
do.call('structure', outclass)
to produce
the desired output.
These two basic algorithms ("Numeric" and
"Character") are the same if proportion
is missing or not numeric: In that case
Interp
throws an error.
We now consider "Character" first, because it's domain of applicability is easier to describe. The "Numeric" algorithm is used in all other cases
1. "CHARACTER"
* 1.1. The "CHARACTER" algorithm is used when
at least one of x
and y
is neither
logical, integer, numeric, complex nor raw and
satisfies one of the following two additional
conditions:
** 1.1.1. Either x
or y
is
character.
** 1.1.2. class(unclass(.))
for at least
one of x
and y
is either character
or integer.
NOTE: The strengths and weaknesses of 1.1.2 can
be seen in considering factors and integer
vectors of class zoo
: For
both, class(unclass(.))
is integer. For
factors, we want to use as.character(.)
.
For zoo
objects with
coredata
of class integer,
we would want to use numeric interpolation.
This is not allowed with the current code but
could be easily implemented by writing
Interp.zoo
.
* 1.2. If either x
or y
is missing
or has length
0, the one that is
provided is returned unchanged.
* 1.3. Next determine the class of the output.
This depends on whether neither, one or both of
x
and y
have one of the six classes
of atomic vectors (logical, integer, numeric,
complex, raw, character):
** 1.3.1. If both x
and y
have
one of the six atomic classes and one is
character, return a character object.
** 1.3.2. If only one of x
and y
have an atomic class, return an object of the
class of the other.
** 1.3.3. If neither of x
nor y
have a basic class, return an object with the
class of y
.
* 1.4. Set pLength1 <-
(length(proportion) == 1)
:
** 1.4.1. If(pLength1)
do the linear
interpolation on cumsum(nchar(.))
.
** 1.4.2. Else do the linear interpolation on
nchar
.
* 1.5. Next check x
, y
and
proportion
for comparable lengths: If
all have length 0, return an object of the
appropriate class. Otherwise, call
compareLengths(x, proportion)
,
compareLengths(y, proportion)
, and
compareLengths(x, y)
.
* 1.6. Extend x
, y
, and
proportion
to the length of the longest
using rep
.
* 1.7. nchOut
<- the number of
characters to output using numeric
interpolation and rounding the result to
integer.
* 1.8. Return substring(y, 1, nchOut)
except when the number of characters from
x
exceed those from y
, in which
case return substring(x, 1, nchOut)
.
[NOTE: This meets the naive end conditions
that the number of characters matches that of
x
when proportion
is 0 and matches
that of y
when proportion
is 1.
This can be used to "erase" characters moving
from one frame to the next in a video. See the
examples.
2. "NUMERIC"
* 2.1. Confirm that this does NOT satisfy the condition for the "Character" algorithm.
* 2.2. If either x
or y
is missing
or has length
0, return the one
provided.
* 2.3. Next determine the class of the output.
As for "Character" described in section 1.3, this
depends on whether neither, one or both of
x
and y
have a basic class other
than character (logical, integer, numeric,
complex, raw):
** 2.3.1. If proportion
<= 0, return
x
unchanged. If proportion
>= 1,
return y
unchanged.
** 2.3.2. If neither x
nor y
has
a basic class, return an object of class equal
that of y
.
** 2.3.3. If exactly one of x
and
y
does not have a basic class, return an
object of class determined by
class(unclass(.))
of the non-basic
argument.
** 2.3.4. When interpolating between two objects
of class raw, convert the interpolant back to
class raw. Do this even when 2.3.2 or 2.3.3
applies and class(unclass(.))
of both
x
and y
are of class raw.
* 2.4. Next check x
, y
and
proportion
for comparable lengths: If
all have length 0, return an object of the
appropriate class. Otherwise, call
compareLengths(x, proportion)
,
compareLengths(y, proportion)
, and
compareLengths(x, y)
.
* 2.5. Compute the desired interpolation and convert it to the required class per step 2.3 above.
Value
Interp
returns a vector whose class is
described in "* 1.3" and "* 2.3" in "Details"
above.
InterpChkArgs
returns a list or throws an
error as described in "Details" above.
Author(s)
Spencer Graves
References
The
Writing R Extensions manual (available via
help.start()
) lists six different classes
of atomic vectors: logical
,
integer
, numeric
,
complex
, raw
and
character
. See also Wickham,
Hadley (2014) Advanced R, especially
Wickham
(2013, section on "Atomic vectors" in the
chapter on "Data structures").
See Also
Many other packages have functions with names
like interp
, interp1
, and
interpolate
. Some do one-dimensional
interpolation. Others do two-dimensional
interpolation. Some offer different kinds of
interpolation beyond linear. At least one is a
wrapper for approx
.
Examples
##
## 1. numerics
##
# 1.1. standard
xNum <- interpChar(1:3, 4:5, (0:3)/4)
# answer
xN. <- c(1, 2.75, 3.5, 4)
all.equal(xNum, xN.)
# 1.2. with x but not y:
# return that vector with a warning
xN1 <- Interp(1:4, p=.5)
# answer
xN1. <- 1:4
all.equal(xN1, xN1.)
##
## 2. Single character vector
##
i.5 <- Interp(c('a', 'bc', 'def'), character(0), p=0.3)
# with y = NULL or character(0),
# Interp returns x
all.equal(i.5, c('a', 'bc', 'def'))
i.5b <- Interp('', c('a', 'bc', 'def'), p=0.3)
# Cumulative characters (length(proportion)=1):
# 0.3*(total 6 characters) = 1.2 characters
i.5. <- c('a', 'b', '')
all.equal(i.5b, i.5.)
##
## 3. Reverse character example
##
i.5c <- Interp(c('a', 'bc', 'def'), '', 0.3)
# check: 0.7*(total 6 characers) = 4.2 characters
i.5c. <- c('a', 'bc', 'd')
all.equal(i.5c, i.5c.)
##
## 4. More complicated example
##
xCh <- Interp('', c('Do it', 'with R.'),
c(0, .5, .9))
# answer
xCh. <- c('', 'with', 'Do i')
all.equal(xCh, xCh.)
##
## 5. Still more complicated
##
xC2 <- Interp(c('a', 'fabulous', 'bug'),
c('bigger or', 'just', 'big'),
c(.3, .3, 1) )
x.y.longer <- c('bigger or', 'fabulous', 'big')
# use y with ties
# nch smaller 1 4 3
# nch larger 9 8 3
# d.char 8, 4, 0
# prop .3, .7, 1
# prop*d.char 2.4, 2.8, 0
# smaller+p*d 3, 7, 3
xC2. <- c('big', 'fabulou', 'big')
all.equal(xC2, xC2.)
##
## 6. with one NULL
##
null1 <- Interp(NULL, 1, .3)
all.equal(null1, 1)
null2 <- Interp('abc', NULL, .3)
all.equal(null2, 'abc')
##
## 7. length=0
##
log0 <- interpChar(logical(0), 2, .6)
all.equal(log0, 1.2)
##
## 8. Date
##
(Jan1.1980 <- as.Date('1980-01-01'))
Jan1.1972i <- Interp(0, Jan1.1980, .2)
# check
Jan1.1972 <- as.Date('1972-01-01')
all.equal(Jan1.1972, round(Jan1.1972i))
##
## 9. POSIXct
##
(Jan1.1980c <- as.POSIXct(Jan1.1980))
(Jan1.1972ci <- Interp(0, Jan1.1980c, .2))
# check
(Jan1.1972ct <- as.POSIXct(Jan1.1972))
abs(difftime(Jan1.1972ct, Jan1.1972ci,
units="days"))<0.5