mixed <- c("AAA", 10, 185.40) # one character, two numbers
print(mixed) # -> [1] "AAA" "10" "185.4"[1] "AAA" "10" "185.4"
print(class(mixed)) # -> [1] "character"[1] "character"
A list holds values of different types at once: text, numbers, and other lists side by side. A vector cannot. c() forces everything it is given down to a single type.
In this lesson I describe one position as a list, read parts of it out, then build a list of positions and total the book two ways.
Put a ticker and two numbers in one vector and R turns the numbers into text.
[1] "AAA" "10" "185.4"
[1] "character"
The quotes around "10" and "185.4" are the giveaway. You can no longer multiply them.
list() takes the same three values and leaves each one as it was. Name the parts as you go.
[1] "list"
[1] 3
[1] "ticker" "shares" "price"
length() counts elements. Printing the list shows each element under its name.
$ticker
[1] "AAA"
$shares
[1] 10
$price
[1] 185.4
str() gives the same thing in three compact lines, with the type of each element.
List of 3
$ ticker: chr "AAA"
$ shares: num 10
$ price : num 185
chr is character and num is numeric, so the types survived. str() rounds 185.4 to 185 for display only; the stored value is unchanged.
[[ ]] reaches inside and hands you the element. $ does the same with less typing.
[1] 10
[1] 10
[1] "numeric"
[1] 1854
[ ] does not reach inside. It selects part of the list and hands back a shorter list.
$shares
[1] 10
[1] "list"
[1] "numeric"
Same element, two answers: pos["shares"] is a list of length one, pos[["shares"]] is the number 10. Multiplying the first by a price fails, because you cannot multiply a list.
Position works as well as name. pos[[2]] is the second element.
An element of a list can itself be a list. That is how you hold a book of positions.
[1] 3
[1] "list"
[1] "CCC"
positions[[2]] is the second position and $ticker reaches into it.
Now loop over the book. Each pass gives you one position list, and p$shares * p$price values it.
AAA is worth 1854
CCC is worth 1640.8
DDD is worth 2575
[1] 6069.8
sapply() runs a function on every element of a list and returns a vector.
[1] 1854.0 1640.8 2575.0
[1] "numeric"
[1] 6069.8
The result is a plain numeric vector, so sum() works on it directly. The loop printed as it went; sapply() collects instead.
Pull the tickers the same way and hang them on the vector as names.
AAA CCC DDD
1854.0 1640.8 2575.0
AAA CCC DDD
0.305 0.270 0.424
Add a fourth position to positions: 30 shares of BBB at 92.50. Rebuild values with sapply(), name it, and print the weights.
positions[[4]] <- list(ticker = "BBB", shares = 30, price = 92.50) # append by index
print(length(positions)) # -> [1] 4
vals <- sapply(positions, function(p) p$shares * p$price) # value each position
names(vals) <- sapply(positions, function(p) p$ticker) # label with the tickers
print(vals)
# -> AAA CCC DDD BBB
# -> 1854.0 1640.8 2575.0 2775.0
print(sum(vals)) # -> [1] 8844.8
print(round(vals / sum(vals), 3)) # the four weights
# -> AAA CCC DDD BBB
# -> 0.210 0.186 0.291 0.314A data frame is a list whose elements are columns of equal length. That is Lesson 11.