my_logi <- c(TRUE, FALSE)
typeof(x = my_logi)[1] "logical"
The below tutorials are all focused on neat features of the R programming language. See sub-headings for more specifics!
The R programming language is extremely useful for a variety of data science tasks. It–and other object-oriented programming languages–allow storing values in “objects” and then using those objects to re-call and use the values to which they are bound. In order to combine different “types” of values, R has to “coerce” one or both of the values into a shared type (sometimes a.k.a. “class” depending on what you’re working on).
The order of this coercion is logical integer double character. Logicals are the most specific type of atomic vector and the order proceeds to characters which are the most general type. It might be helpful to consider some examples. Let’s begin by making one object for each atomic type (identified above).
Now that we have those, let’s combine them in sequence so we can see the coercion rules in action!
You may have noticed that the above examples are missing some classes of object with which you may work regularly. These were absent from the above examples because the first component of this tip is restricted only to “type” coercion while you may be thinking of “class” coercion. See below for some examples that may address what felt missing above.
“Numeric” values are technically inclusive of both integers and doubles. The reason to avoid that phrasing earlier was just to be more precise about the coercion rules between integers and doubles.
Factors are a special case of an integer. This does mean that coercing a factor can have surprising results in some cases.
[1] a b c
Levels: a b c
Dates are a special case of a double. They represent the number of days since January 1st, 1970. Like factors, this means that coercion can behave in a way that surprises you.
Date-times are a special case of a double. They represent the number of seconds since January 1st, 1970. Just like dates, this can make coercion surprising here as well.
[1] "double"
[1] "POSIXct" "POSIXt"
[1] "a" "b" "c" "1728860400"
[1] "character"
Many programming languages rely on being able to signal “conditions” when code doesn’t work as intended. These conditions range from effectively ‘for your information’ notes all the way to full-blown errors. See the tabs below for the three most common conditions in R
Messages indicate that an action has been taken on the user’s behalf but not necessarily a problem. These can be useful to explicitly inform a user about an assumed default value or–for code that iterates for a long time–reassure users that the function is still working.
Warnings indicate that something has gone wrong but the function could at least partially recover. These can be useful when some facet of a user’s input is incorrect but the code can still complete. I often uses warnings in my custom functions that have at least one argument that expects a logical (i.e., T or F). If the user supplies anything other than a logical, I return a warning and coerce that argument to whatever default logical I originally defined.
Errors indicate that that the function cannot continue and execution must stop. Including custom input checks with informative messages in an important facet of package development! And in non-function code, error messages are your first indicating that something is not working as it should.
When iterating a given operation it is common to loop across some integer. For example, maybe you’re looping across a list and want to use the numeric position of each element of the list. Typically, this is accomplished like so:
Processing a
Processing b
Processing c
This works in this case but if the vector of values has no elements, the loop will behave unexpectedly. This is because 1:length of an empty vector returns 1 and 0! Let’s demonstrate this here:
Processing
Processing
[1] 1 0
See how the loop still appears to work but isn’t returning values that might be expected? This can be especially challenging to debug with a more complex (i.e., more realistic) loop. However, we can reformat the first part of the loop to use seq_along instead of 1:length. The loop will still not work but it will be more clear that the issue is with your initial vector of inputs.
seq_along has an along.with argument but for conciseness I’ve let it be implicit in this demo
integer(0)
[, [[, and $In R, there are three primary methods of selecting elements in an object – [, [[, and $. However, many R users don’t actually know how the three methods differ from one another. The following attempts to clarify this! Let’s start with a multi-element list and then check out an example of each.
If x is a train with multiple cars where each car may contain some number of items, x[1] grabs the whole first train car. This means that the extracted bit is still the same type of data as the original object; in this case that means we still have a list, just this time it has only a single element.
Using either element position or element name (if there is one) is supported.
If x is a train with multiple cars where each car may contain some number of items, x[[1]] grabs the contents of the whole first train car. This means that the type of data changes to whatever is stored in that element. In this case that means we now have a vector.
Again, both element position and element name (if there is one) are supported.
[[ versus $The above examples show how [[ and $ function similarly but there is an important caveat to this! If name is an object containing one of the names in x, then the two methods differ. x[[name]] will get the entity that matches the value of name while x$name will get an entity that is itself named name. See an example below:
wanted_bit is interpreted as "e" because that is the value bound to that object.
[1] 5