Understanding the step cannot be zero error in Julia Language? - julia

I need a vector of UnitRanges as follows:
[2:5, 3:6, 4:7, 5:8]
when I try to run this (2:5):(5:8), I get an error of "ArgumentError: step cannot be zero."
Is there a way of creating a UnitRange array using UnitRange itself?

It sounds like you want to map or broadcast : over the elements in the two arguments. Just do it explicitly:
julia> map(:, 2:5, 5:8)
4-element Array{UnitRange{Int64},1}:
2:5
3:6
4:7
5:8
Now, ideally you'd also be able to write this as (2:5) .: (5:8) — you'd dot the : operator to broadcast it — but since : is used for so many things and since this isn't a very common use-case we've not enabled the dotting of :. You can, however, use the non-infix form and dot that:
julia> (:).(2:5, 5:8)
4-element Array{UnitRange{Int64},1}:
2:5
3:6
4:7
5:8
As for the error message you're getting, it's because the first thing : tries to do is determine the length, assuming its two arguments are scalars. To do this it subtracts the first argument from the second:
julia> (5:8) - (2:5)
ERROR: ArgumentError: step cannot be zero
That fails because it's trying to create a step range that's effectively 3:0:3 and has a length of 4.

Related

How to create a ones array in Julia?

In many Machine Learning use cases, you need to create an array filled with ones, with specific dimensions. In Python, I would use np.ones((2, 1)). What is the analog version of this in Julia?
Julia has a built in ones function which can be used as follows:
julia> ones(1,2)
1×2 Matrix{Float64}:
1.0 1.0
You can read more about the ones function in the Julia docs.
The answer by Logan is excellent. You can just use the ones function.
BUT, you can also often not use it.
For instance, a common use of a vector of ones is to multiply that vector times another vector so you get a matrix where each row just has the same value as in the corresponding element of the matrix. Then you can add that matrix to something. This allows you add the values of a vector to the corresponding rows of a matrix. You get code like this:
>>> A = np.random.rand(4,3)
>>> x = np.random.rand(4)
array([0.01250529, 0.9620139 , 0.70991563, 0.99795451])
>>> A + np.reshape(np.ones(3), (1,3)) * np.reshape(x, (4,1))
array([[0.09141967, 0.83982525, 0.16960596],
[1.39104681, 1.10755182, 1.60876696],
[1.14249757, 1.68167344, 1.64738165],
[1.10653393, 1.45162139, 1.23878815]])
This is actually a lot of extra work for the computer because Python can't optimize this and a lot of extra work is going on. You could also use so called broadcasting to do this extension more simply, but you still have to get x into the right shape:
>>> A + x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (4,3) (4,)
>>> A + np.reshape(x, (4,1))
array([[0.09141967, 0.83982525, 0.16960596],
[1.39104681, 1.10755182, 1.60876696],
[1.14249757, 1.68167344, 1.64738165],
[1.10653393, 1.45162139, 1.23878815]])
In Julia, the extension of the vector to the same shape as the matrix you to which you want to add can be done more simply using the broadcast operator. Thus, the code above simplifies to
julia> A = rand(4,3)
4×3 Matrix{Float64}:
0.885593 0.494999 0.534039
0.915725 0.479218 0.229797
0.739122 0.670486 0.247376
0.419879 0.857314 0.652547
julia> x = rand(4)
4-element Vector{Float64}:
0.9574839624590326
0.9736140903654276
0.6051487944513263
0.3581090323172089
julia> A .+ x
4×3 Matrix{Float64}:
1.84308 1.45248 1.49152
1.88934 1.45283 1.20341
1.34427 1.27563 0.852524
0.777988 1.21542 1.01066
One reason that this works better is because there is less noise in the syntax because arrays are primitive to Julia.
Much more importantly, though, compiler sees the use of the broadcast operator and it can generate very efficient code (and can even vectorize it). In fact, x doesn't even have to be an actual vector as long as it has a few of the same methods defined for it.
In fact, if you really do need a vector or matrix of all ones (or some other constant) you can use broadcast with scalars as well
julia> A .+ 1
4×3 Matrix{Float64}:
1.88559 1.495 1.53404
1.91572 1.47922 1.2298
1.73912 1.67049 1.24738
1.41988 1.85731 1.65255

Pass vector as command line argument in Julia

Is there a way to pass a vector variable as a command line argument in Julia? In my case I have two arguments: an integer and a vector of integers. While I can easily parse the first argument, I didn't find any pleasant way to parse a vector. For now I simply set the vector to be v = parse.(Int, ARGS[2:end]) but it is quite confusing since the items of the vector are treated as arguments. Is there a some special syntax to treat such cases?
I think your current solution is fine as it is, and in line with the way many command-line tools do things.
If you really want to pass your whole array as one command-line argument, you'll have to:
somehow make sure it is correctly parsed as one argument by the shell
parse it as an array within Julia
Both steps vary depending on the syntax you want to use.
Two examples:
example 1: Julia-like syntax
shell$ julia myscript.jl 42 "[1,2,3]"
i = 42
v = [1, 2, 3]
We can take advantage of the Julia parser being able to parse such arrays (but let's be cautious about not evaluating arbitrary julia code input by the user):
# First argument: an integer
i = parse(Int, ARGS[1])
# Second argument, a Vector{Int} in Julia-like format: "[1, 2, 3]"
v = let expr = Meta.parse(ARGS[2])
#assert expr.head == :vect
Int.(expr.args)
end
#show i
#show v
Example 2: space- or comma-separated values
shell$ julia myscript.jl 42 "1,2,3"
i = 42
v = [1, 2, 3]
Here, we can use DelimitedFiles to parse the array (change the delimiter to whatever you like):
# First argument: an integer
i = parse(Int, ARGS[1])
# Second argument, a Vector{Int} as comma-separated values
using DelimitedFiles
v = reshape(readdlm(IOBuffer(ARGS[2]), ',', Int), :)
# set the delimiter here ^
#show i
#show v

seq function weird output in R

I was playing with R loops when I got this output
printLoop<-function(size){
for(index in seq(size))
cat("\n Index is at:",index)
}
And since I have started to program in R just few days ago.I here made a simple print function.I gave different inputs to this but on giving input 0 I got following output.
Index is at: 1
Index is at: 0
Why is that?
So I thought that may be there is something wrong in seq() and by passing 0 to it I got results 0 and 1 again; my question is why?
In addition to my comment above, see ?seq, relevant/important points bolded:
Typical usages are
seq(from, to)
seq(from, to, by= )
seq(from, to, length.out= )
seq(along.with= )
seq(from)
seq(length.out= )
The first form generates
the sequence from, from+/-1, ..., to (identical to from:to).
The second form generates from, from+by, ..., up to the sequence value
less than or equal to to. Specifying to - from and by of opposite
signs is an error. Note that the computed final value can go just
beyond to to allow for rounding error, but is truncated to to. (‘Just
beyond’ is by up to 1e-10 times abs(from - to).)
The third generates a sequence of length.out equally spaced values
from from to to. (length.out is usually abbreviated to length or len,
and seq_len is much faster.)
The fourth form generates the integer sequence 1, 2, ...,
length(along.with). (along.with is usually abbreviated to along, and
seq_along is much faster.)
The fifth form generates the sequence 1, 2, ..., length(from) (as if
argument along.with had been specified), unless the argument is
numeric of length 1 when it is interpreted as 1:from (even for seq(0)
for compatibility with S). Using either seq_along or seq_len is much
preferred (unless strict S compatibility is essential).
The final form generates the integer sequence 1, 2, ..., length.out
unless length.out = 0, when it generates integer(0).
So one way to specify your function to get what seems like your desired output is:
printLoop<-function(size){
for(index in seq(to=size,by=1L))
cat("\n Index is at:",index)
}
> printLoop(0L)
Error in seq.default(to = size, by = 1L) : wrong sign in 'by' argument
(note that if you don't want an error, you could just use seq_len(size))
Which is simply obeying the other admonishment of ?seq, namely:
The interpretation of the unnamed arguments of seq and seq.int is not standard, and it is recommended always to name the arguments when programming.

Using lapply with Dates and the minus function

I have a vector of dates and a vector of number-of-days.
dates <- seq(Sys.Date(), Sys.Date()+10, by='day')
number.of.days <- 1:4
I need to get a list with an entry for each number-of-days, where each entry in the list is the dates vector minus the corresponding number-of-days, ie.,
list(dates-1, dates-2, dates-3, dates-4)
The defintion of - (function (e1, e2) .Primitive("-")) indicates that its first and second arguments are e1 and e2, respectively. So the following should work.
lapply(number.of.days, `-`, e1=dates)
But it raises an error.
Error in -.Date(X[[i]], ...) : can only subtract from "Date" objects
Furthermore, the following does work:
lapply(number.of.days, function(e1, e2) e1 - e2, e1=dates)
Is this a feature or a bug?
You can use:
lapply(number.of.days, `-.Date`, e1=dates)
Part of the problem is - is a primitive which doesn't do argument matching. Notice how these are the same:
> `-`(e1=5, e2=3)
[1] 2
> `-`(e2=5, e1=3)
[1] 2
From R Language Definition:
This subsection applies to closures but not to primitive functions. The latter typically ignore tags and do positional matching, but their help pages should be consulted for exceptions, which include log, round, signif, rep and seq.int.
So in your case, you end up using dates as the second argument to - even though you attempt to specify it as the first. By using the "Date" method for -, which is not a primitive, we can get it to work.
So technically, the behavior you are seeing is a feature, or perhaps a "documented inconsistency". The part that could possibly considered a bug is that R will do a multiple dispatch to a "Date" method for - despite that method not supporting non-date arguments as the first argument:
> 1:4 - dates # dispatches to `-.Date` despite first argument not being date
Error in `-.Date`(1:4, dates) : can only subtract from "Date" objects
You might be better off using POSIXt dates. They're a bit more flexible, for example if you wanted to add a week or year. The equivalent answer to #BrodieG using lubridate functionality to work with POSIXt:
dates <- ymd(seq(Sys.Date(), Sys.Date()+10, by='day'))
number.of.days <- 1:4
list(dates-1, dates-2, dates-3, dates-4)
lapply(number.of.days, `-.POSIXt`, e1=dates)
Also, how's the fishing in Philly? :)

Convert character vector to numeric vector in R for value assignment?

I have:
z = data.frame(x1=a, x2=b, x3=c, etc)
I am trying to do:
for (i in 1:10)
{
paste(c('N'),i,sep="") -> paste(c('z$x'),i,sep="")
}
Problems:
paste(c('z$x'),i,sep="") yields "z$x1", "z$x1" instead of calling the actual values. I need the expression to be evaluated. I tried as.numeric, eval. Neither seemed to work.
paste(c('N'),i,sep="") yields "N1", "N2". I need the expression to be merely used as name. If I try to assign it a value such as paste(c('N'),5,sep="") -> 5, ie "N5" -> 5 instead of N5 -> 5, I get target of assignment expands to non-language object.
This task is pretty trivial since I can simply do:
N1 = x1...
N2 = x2...
etc, but I want to learn something new
I'd suggest using something like for( i in 1:10 ) z[,i] <- N[,i]...
BUT, since you said you want to learn something new, you can play around with parse and substitute.
NOTE: these little tools are funny, but experienced users (not me) avoid them.
This is called "computing on the language". It's very interesting, and it helps understanding the way R works. Let me try to give an intro:
The basic language construct is a constant, like a numeric or character vector. It is trivial because it is not different from its "unevaluated" version, but it is one of the building blocks for more complicated expressions.
The (officially) basic language object is the symbol, also known as a name. It's nothing but a pointer to another object, i.e., a token that identifies another object which may or may not exist. For instance, if you run x <- 10, then x is a symbol that refers to the value 10. In other words, evaluating the symbol x yields the numeric vector 10. Evaluating a non-existant symbol yields an error.
A symbol looks like a character string, but it is not. You can turn a string into a symbol with as.symbol("x").
The next language object is the call. This is a recursive object, implemented as a list whose elements are either constants, symbols, or another calls. The first element must not be a constant, because it must evaluate to the real function that will be called. The other elements are the arguments to this function.
If the first argument does not evaluate to an existing function, R will throw either Error: attempt to apply non-function or Error: could not find function "x" (if the first argument is a symbol that is undefined or points to something other than a function).
Example: the code line f(x, y+z, 2) will be parsed as a list of 4 elements, the first being f (as a symbol), the second being x (another symbol), the third another call, and the fourth a numeric constant. The third element y+z, is just a function with two arguments, so it parses as a list of three names: '+', y and z.
Finally, there is also the expression object, that is a list of calls/symbols/constants, that are meant to be evaluated one by one.
You'll find lots of information here:
https://github.com/hadley/devtools/wiki/Computing-on-the-language
OK, now let's get back to your question :-)
What you have tried does not work because the output of paste is a character string, and the assignment function expects as its first argument something that evaluates to a symbol, to be either created or modified. Alternativelly, the first argument can also evaluate to a call associated with a replacement function. These are a little trickier, but they are handled by the assignment function itself, not by the parser.
The error message you see, target of assignment expands to non-language object, is triggered by the assignment function, precisely because your target evaluates to a string.
We can fix that building up a call that has the symbols you want in the right places. The most "brute force" method is to put everything inside a string and use parse:
parse(text=paste('N',i," -> ",'z$x',i,sep=""))
Another way to get there is to use substitute:
substitute(x -> y, list(x=as.symbol(paste("N",i,sep="")), y=substitute(z$w, list(w=paste("x",i,sep="")))))
the inner substitute creates the calls z$x1, z$x2 etc. The outer substitute puts this call as the taget of the assignment, and the symbols N1, N2 etc as the values.
parse results in an expression, and substitute in a call. Both can be passed to eval to get the same result.
Just one final note: I repeat that all this is intended as a didactic example, to help understanding the inner workings of the language, but it is far from good programming practice to use parse and substitute, except when there is really no alternative.
A data.frame is a named list. It usually good practice, and idiomatically R-ish not to have lots of objects in the global environment, but to have related (or similar) objects in lists and to use lapply etc.
You could use list2env to multiassign the named elements of your list (the columns in your data.frame) to the global environment
DD <- data.frame(x = 1:3, y = letters[1:3], z = 3:1)
list2env(DD, envir = parent.frame())
## <environment: R_GlobalEnv>
## ta da, x, y and z now exist within the global environment
x
## [1] 1 2 3
y
## [1] a b c
## Levels: a b c
z
## [1] 3 2 1
I am not exactly sure what you are trying to accomplish. But here is a guess:
### Create a data.frame using the alphabet
data <- data.frame(x = 'a', y = 'b', z = 'c')
### Create a numerical index corresponding to the letter position in the alphabet
index <- which(tolower(letters[1:26]) == data[1, ])
### Use an 'lapply' to apply a function to every element in 'index'; creates a list
val <- lapply(index, function(x) {
paste('N', x, sep = '')
})
### Assign names to our list
names(val) <- names(data)
### Observe the result
val$x

Resources