General Guidelines
Homework 3
Stats 20 Lec 1 Winter 2022
Please use R Markdown for your submission. Include the following files: • Your .Rmd file.
Copyright By PowCoder代写 加微信 powcoder
• The compiled/knitted HTML document.
Name your .Rmd file with the convention 123456789_stats20_hw0.Rmd, where 123456789 is replaced with your UID and hw0 is updated to the actual homework number. Include your first and last name and UID in your exam as well. When you knit to HTML, the HTML file will inherit the same naming convention.
The knitted document should be clear, well-formatted, and contain all relevant R code, output, and explanations. R code style should follow the Tidyverse style guide: https://style.tidyverse.org/.
Any and all course material, including these homework questions, may not be posted online or shared with anyone at any time without explicit written permission by the instructor ( ), even after the quarter is over. Failure to comply is a breach of academic integrity.
Note: All questions on this homework should be done using only functions or syntax discussed in Chapters 1–4 of the lecture notes. No credit will be given for use of outside functions.
Basic Questions
Collaboration on basic questions must adhere to Level 0 collaboration described in the Stats 20 Collaboration Policy.
Several exercises throughout this course will ask you to code your own version of basic built-in functions from scratch. While you will likely not need to rewrite existing functions from scratch when using R in practice, the thought process of thinking through and writing these functions allows you to build your skills in breaking down complicated problems into simpler steps and more deeply understanding the fundamental toolkit you are building throughout the course.
A general strategy for how to think through writing functions from scratch:
1. Come up with small general examples and think about what your function ideally should do for those examples. Do you notice patterns or using similar logic for every example?
2. Formalize and generalize the logic you used in your small examples to the general case. How should your function work on the intended input argument(s) in general? Outline or describe the steps your function needs to do to output the desired result.
3. Consider any edge cases, i.e., valid inputs that your function is supposed to work on but may not use the same logic as the general case to work. See if the logic you used in general extends to the edge case. If not, think about whether the general case can be modified to accommodate the edge case.
Now that we have introduced flow control statements (loops and if/if-else statements), we can consider more complex algorithms and functions, but the general strategy remains the same.
Question 1
The objective of this question is to give practice with logical indexing.
Suppose Andy Dwyer tracks his commute time to his women’s studies class for ten days and records the following times (in minutes):
14 12 20 19 15 20 28 20 20 18
Store Andy’s commute times as a vector in your workspace called commute_times. Use a logical index to determine which days Andy had a commute time that was more than one standard deviation away (longer or shorter) from the average (mean) commute time? What were those commute times?
Hint: In addition to the lecture notes, you may use the abs() function, if necessary. The abs() function computes the absolute value of the elements of a numeric vector.
Using the same logical index from (a), determine which days Andy had a commute time that was within one standard deviation (longer or shorter) of the mean commute time? What were those commute times?
Using the same logical index from (a), what proportion of days did Andy have a commute time that was within one standard deviation of the mean commute time?
Hint: Can arithmetic operators/functions for numeric vectors work for logical vectors? What do sum() and mean() compute for logical vectors?
Question 2
The objective of this question is to help further your understanding of Boolean operators and what NA represents.
Logical vectors in R can contain NA in addition to TRUE and FALSE. An NA in a logical context can be interpreted as “unknown.” Consider the following commands:
NA & FALSE
NA | FALSE
Explain why there is a difference in the output of these four commands. Why are they not all NA? Hint: Does the output rely on knowing what the unknown value NA represents?
Question 3
The objective of this question is to review the concept of vectorization and practice using logical expressions.
Note: You may not use a loop for this question.
Recall the get_minimum_coins() function from Homework 1 Question 7(c), which inputs a positive (whole) number of cents (call the argument cents) and outputs the minimum number of coins required to equal that number of cents.
Is the get_minimum_coins() function (as you wrote it in Homework 1) vectorized? Why or why not? (b)
In Homework 1 Question 7(e), you used reasoning to explain that the numbers of cents less than 100 which require the most coins are 94 and 99. With a single command (i.e., one line of code), verify your answer with your get_minimum_coins() function.
Hint 1: The output of your single command should be a vector with the two values 94 and 99. You should not display/print the results for every number of cents less than 100.
Hint 2: If the single command is too challenging to come up with all at once, first find a solution using several commands, then condense the operations into a single line.
Question 4
The objective of this question is to give practice with writing a function using a for loop and an if statement, as well as to help your understanding of how to deal with NA values.
Write a function called my_min() that computes the minimum of a vector without the min(), max(), range(), fivenum(), summary(), or sort() functions. Include an optional logical argument called na.rm that specifies whether to remove NAs. The output of my_min(x) and min() should be identical for any vector x.
Hint: Optional arguments (in general) have default values so that they do not need to be specified by the user. What should be the default value of the na.rm argument? That is, should the default behavior be to remove NAs or keep them?
Test your my_min() function from (a) with the following inputs: (i) c(4, 1, 0, 2, -3, -5, -4)
(ii) c(“bears”, “beets”, ” “)
(iv) c(“Pawnee”, “rules”, “Eagleton”, NA), with na.rm = TRUE and na.rm = FALSE
(v) NA, with na.rm = TRUE and na.rm = FALSE
Question 5
The objective of this question is to give practice with while() loops and writing cleaner code. Consider the while() loop below that computes all Fibonacci numbers less than 500.
full_fib <- c(fib1, fib2) while (fib1 + fib2 < 500) {
old_fib2 <- fib2
fib2 <- fib1 + fib2
full_fib <- c(full_fib, fib2)
fib1 <- old_fib2
} full_fib
[1] 1 1 2 3 5 8 13 21 34 55 89 144 233 377
The variable old_fib2 is not actually necessary. Rewrite the while() loop with the update of fib1 based on just the current values of fib1 and fib2.
In fact, fib1 and fib2 are not necessary either. Rewrite the while() loop without using any variables except full_fib.
Determine the number of Fibonacci numbers less than 1,000,000,000 = 109.
Intermediate Questions
Collaboration on intermediate questions must adhere to Level 1 collaboration described in the Stats 20 Collaboration Policy.
Question 6
The objective of this question is to introduce and give practice with the expanded order of operations. Recall the standard PEMDAS order of operations:
• Parentheses ()
• Exponents ˆ
• Multiplication and Division *, / • Addition and Subtraction +, -
We have now learned several additional operations in R to consider. The combined order of operations is: • Parentheses ()
• Exponents ˆ
• Unary operators -, + (changing the sign of a number, e.g. -1)
• Colon operator : (making a regular sequence)
• Infix operators of the form %xyz% (e.g., mod %%, integer division %/%, or matrix multiplication %*%) • Multiplication and Division *, /
• Addition and subtraction +, -
• Relational operators >, >=, <, <=, ==, !=
• Logical negation !
• Logical AND &, &&
• Logical OR |, ||
• Assignment operator <-
Use only parentheses, the order of operations, and coercion rules (i.e., the mode hierarchy) to change the following line of code so that the jerry object will contain the numeric vector c(2, 1), and the statement should not produce a warning. You may not use type casting functions for this question.
[1] FALSE FALSE TRUE TRUE TRUE TRUE TRUE
Hint 1: First use parentheses to understand what is the order of operations as written, then consider what computations/coercions need to occur to get a numeric vector of length 2.
Hint 2: A minimal/ideal solution contains no more than three sets of parentheses.
jerry <- 2:8 * 5 %% 3ˆ-2:7 > 2
Question 7
The objective of this question is to introduce the ifelse() function and give practice with vectorization. (a)
Write a function called my_ifelse() that implements a vector form of the if-else statement without the ifelse() function. That is, the ith element of my_ifelse(test, yes, no) will be yes[i] if test[i] is TRUE and no[i] if test[i] is FALSE. Values of yes or no should be recycled if either is shorter than test.
Hint: This can be written as a loop, but a vectorized solution is better. (b)
Verify that your my_ifelse() function works by executing the following commands:
Use your my_ifelse() function to write my_abs() and my_sign() functions that, respectively, compute the absolute values and signs of the elements of a numeric vector. The respective outputs of my_abs(x) and my_sign() should be identical to abs(x) and sign(x) for any numeric vector x.
Hint: It may be helpful to use my_abs() when writing my_sign().
x <- (1:10) * pi
my_ifelse(x %% 1 >= 0.5, x %/% 1 + 1, x %/% 1)
Question 8
The objective of this question is to introduce the concept of recursion, as well as give further practice with flow control statements and following instructions given in pseudocode.
There are many ways to sort a vector. In this problem, you will implement one of the more interesting: the merge sort.
Merge sort is an example of a “divide and conquer” algorithm, which means it solves the problem it is working on by breaking it up into smaller and smaller pieces so that by the time the smaller problems are solved, the larger problem will seem to have magically resolved itself. It is also interesting because it is an example of a recursive algorithm, which means it calls itself (generating Fibonacci numbers is another example of a recursive algorithm).
One way to think of a merge sort is like this: Suppose you were responsible for sorting a stack of papers. You could just sort them all yourself, but who has time for that? So, you find two friends who owe you a favor and you split the stack of papers in half, giving one half to each of your friends and tell them to sort their stacks. Your plan is to simply “merge” their two sorted stacks together after they give them back to you by repeatedly looking at the first paper on each stack and putting the appropriate one of those two stacks next in a new stack, until only that stack remains. The magic part comes in when each of your friends does the same thing, splitting their stacks in half and each giving those smaller stacks to two other friends, and so on. If anyone gets a stack of length 1 or 0 papers, they simply hand it back up the chain.
Here is an example:
Level 1: You
Dasul, Chengyi, Bianca, Hyunjee, Giorgia, Filippo, Eva, 2: You split the vector in two and give it to two others
Dasul, Chengyi, Bianca, , Filippo, Eva, 3: They each split their vectors in two and give them two two others each
Dasul, Chengyi Bianca, , , 4: Each of them split their vectors again and give them to two others
Everybody at level 4 was given a stack of just one paper, so they have already “sorted” their stack and they have them back up the chain:
Level 3: Get back:
Dasul & Chengyi
Merge to and pass up:
Chenyi, Dasul
Level 2: Get back:
Bianca & Hyunjee
Bianca, & , , Giorgia & Albert, , Eva, Filippo, Giorgia
All any one person in the system needs to do is: Take the stack they are given. If the stack is length 1 or zero, immediately return it to the person who gave it to them, otherwise split their stack of papers in two and give each half to someone else to sort. When they get back the two sorted halves, merge them into one sorted stack and pass that back.
Chenyi, Dasul & Bianca, Hyunjee
Merge to and pass up:
Bianca, Chenyi, Dasul, Hyunjee
Level 1: Get back:
Bianca, Chenyi, Dasul, Hyunjee &
Albert, Eva, Filippo, , Bianca, Chenyi, Dasul, Eva, Filippo, Giorgia, Hyunjee
Merge to and pass up:
Eva & , Eva
Read through the following pseudocode:
FUNCTION: merge()
INPUTS: left, right, two sorted numeric vectors
OUTPUT: A single combined sorted vector
merged <- numeric vector of length 0.
WHILE length of left > 0
IF length right > 0
IF the first element of left < the first element of right
merged <- combination of merged and the first element of left
remove the first element of left
merged <- combination of merged and the first element of right
remove the first element of right
merged <- combination of merged and left
remove all the elements of left
OUTPUT combination of merged and right
FUNCTION: merge_sort()
INPUTS: x, a numeric vector
OUTPUT: A vector containing the elements of x, sorted from smallest to largest.
IF length x > 1
split x roughly into half, as two vectors named left and right
sorted_left <- left sorted by merge_sort()
sorted_right <- right sorted by merge_sort()
x <- merge sorted_left and sorted_right with the merge() function
Using the provided pseudocode, write the merge() and merge_sort() functions.
Test your merge_sort() function on the following vectors:
(i) numeric(0) (ii) 7
(iii) 10:1
Advanced Questions
Collaboration on advanced questions must adhere to Level 1 collaboration described in the Stats 20 Collaboration Policy.
Note: Advanced Questions are intended for further enrichment and a deeper challenge, so they will not count against your grade if they are not completed or attempted.
Question 9
Download the dna.RData file from CCLE and save it to your working directory. Then run the following command to load the objects dna1 and dna2 in your workspace:
load("dna.RData")
The dna1 and dna2 vectors represent nucleotide sequences of DNA (deoxyribonucleic acid). The letters A, C, G, and T respectively represent the four nucleotide bases of a DNA strand: adenine, cytosine, guanine, and thymine.
Note: Do not print the entire dna1 and dna2 objects. It is extremely bad practice/style to output an entire object with more than about 100 values in a vector.
Write a function called locate_motif() with two character vector arguments strand and motif that outputs the index of the start of the motif sequence located in the strand vector. If the motif is not found, the locate_motif() function should output integer(0).
Use your locate_motif() function to find the sequence c("G", "A", "T", "T", "A", "C", "A") in the dna1 vector.
Consider the following two DNA sequences:
A substring is a subset of contiguous values in a sequence. The longest shared substring between seq1 and seq2 is "A", "G", "T", starting at index 3 in seq1 and starting at index 2 in seq2.
Using your locate_motif() function from (a), write a function called extract_longest_substring() with two character vector arguments strand1 and strand2 that outputs the longest shared substring. If there is no shared substring, the extract_longest_substring() function should output character(0).
Use your extract_longest_substring() function to find the longest shared substring for the vectors dna1 and dna2.
seq1 <- c("A", "C", "A", "G", "T")
seq2 <- c("T", "A", "G", "T", "A")