Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/nbisweden/workshop-r
Browse files Browse the repository at this point in the history
  • Loading branch information
lokeshbio committed Oct 17, 2024
2 parents ff36d25 + e7b21b4 commit 21134a9
Show file tree
Hide file tree
Showing 2 changed files with 228 additions and 51 deletions.
150 changes: 144 additions & 6 deletions lab_loops.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,36 @@ for (i in vec.a) {
vec.a
```

As you saw in the lecture, this is far less efficient and not by any means easier to type and we hence tend to avoid loops when possible.
This is far less efficient and not by any means easier to type and we hence tend to avoid loops when possible.

<details>
<summary><strong>Extra: Demonstration of time lapse comparison between vectorization and loop</strong></summary>

Let us compare the time of execution of the vectorized version (vector with 10,000 elements):

```{r for.loop.avoid.timing, echo=T}
vec <- c(1:1e6)
ptm <- proc.time()
vec <- vec + 1
proc.time() - ptm # vectorized
```

--

to the loop version:

```{r for.loop.avoid.timing2, echo=T}
vec <- c(1:1e6)
ptm <- proc.time()
for (i in vec) {
vec[i] <- vec[i] + 1
}
proc.time() - ptm # for-loop
```

</details>

</br>

After this exercise you should know:

Expand Down Expand Up @@ -80,7 +109,11 @@ identical(for.sum, rowSums.sum)
identical(for.sum, as.integer(rowSums.sum))
```

2. Another common loop structure that is used is the while loop, which functions much like a for loop, but will only run as long as a test condition is TRUE. Modify your for loop from exercise 1 and make it into a while loop.
2. As you saw in the lecture, another common loop structure that is used is the while loop, which functions much like a for loop, but will only run as long as a test condition is TRUE. Modify your for loop from exercise 1 and make it into a while loop.
<details>
<summary><strong>Tip?</strong></summary>
You can use the number of rows in the matrix as a condition for the while loop.
</details>

```{r,accordion=TRUE}
x <- 1
Expand All @@ -92,14 +125,35 @@ while (x < 100000) {
head(while.sum)
```

3. Create a data frame with two numeric and one character vector. Write a loop that loops over the columns and reports the sum of the column values if it is numeric and the total number of characters if it is a character vector.
**Tips** to count number of characters, you can use `nchar` function.
3. Create a data frame with two numeric and one character vector. Write a loop that loops over the columns and reports the sum of the column values if it is numeric and the total number of characters if it is a character vector.
<details>
<summary><strong>Tip?</strong></summary>
To count number of characters, you can use `nchar` function.
</details>
- Do it first using only if clauses

```{r,accordion=TRUE}
vector1 <- 1:10
vector2 <- c("Odd", "Loop", letters[1:8])
vector3 <- rnorm(10, sd = 10)
dfr1 <- data.frame(vector1, vector2, vector3, stringsAsFactors = FALSE)
sum.vec <- vector()
for(i in 1:ncol(dfr1)) {
if (is.numeric(dfr1[,i])) {
sum.vec[i] <- sum(dfr1[,i])
}
if (is.character(dfr1[,i])) {
sum.vec[i] <- sum(nchar(dfr1[,i]))
}
}
sum.vec
```


- And then modify the loop to use if-else clauses

```{r, accordion=TRUE}
sum.vec <- vector()
for(i in 1:ncol(dfr1)) {
if (is.numeric(dfr1[,i])) {
Expand All @@ -118,19 +172,103 @@ dfr.info <- function(dfr) {
sum.vec <- vector()
for (i in 1:ncol(dfr)) {
if (is.numeric(dfr[,i])) {
sum.vec[i] <- mean(dfr[,i])
sum.vec[i] <- sum(dfr[,i])
} else {
sum.vec[i] <- sum(nchar(dfr[,i]))
}
}
sum.vec
}
#Execute the function
dfr.info(dfr1)
```

5. **Extra exercise** A variation of exercise 3: Create a data frame with three columns: one numeric, one logical, and one character vector. Write a loop that loops over the columns and reports the sum of the column values if it is numeric, the total number of `TRUE`s when is logical and the total number of characters if it is a character vector.
<details>
<summary><strong>Tips?</strong></summary>
To count number of characters, you can use `nchar` function. <br/>
To count number of `TRUE` values, you can use `sum` function.<br/>
Inside the loop, you may want to use the if-else-if structure.<br/>
</details>



```{r,accordion=TRUE}
vector1 <- 1:10
vector2 <- c("Odd", "Loop", letters[1:8])
vector3 <- c(TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE)
dfr2 <- data.frame(vector1, vector2, vector3, stringsAsFactors = FALSE)
sum.vec <- vector()
for(i in 1:ncol(dfr2)) {
if (is.numeric(dfr2[,i])) {
sum.vec[i] <- sum(dfr2[,i])
} else if (is.logical(dfr2[,i])) {
sum.vec[i] <- sum(dfr2[,i])
} else {
sum.vec[i]<-sum(nchar(dfr2[,i]))
}
}
sum.vec
```

5. Read up on the if-else function in R. If possible use the if-else function to answer question 3.

6. In all loops that we tried out we have created the variable where the output is saved outside the loop. Why is this?
</br>
</br>

# Extra material

Do you want to expand on loops, if-else clauses, and functions? Here a bit more extra material!

<details>
<summary><strong>Extra material: The switch function</strong></summary>
If-else clauses operate on logical values. What if we want to take decisions based on non-logical values? Well, if-else will still work by evaluating a number of comparisons, but we can also use **switch**:

```{r switch, echo=T}
switch.demo <- function(x) {
switch(class(x),
logical = cat('logical\n'),
numeric = cat('Numeric\n'),
factor = cat('Factor\n'),
cat('Undefined\n')
)
}
switch.demo(x=TRUE)
switch.demo(x=15)
switch.demo(x=factor('a'))
switch.demo(data.frame())
```

</details>

<details>
<summary><strong>Extra material: The ellipsis argument trick</strong></summary>
What if the authors of, e.g. plot.something wrapper forgot about the `...`?

```{r fns.3dots.trick, echo=T, fig.height = 5, fig.width = 5}
my.plot <- function(x, y) { # Passing downstrem
plot(x, y, las=1, cex.axis=.8, ...)
}
formals(my.plot) <- c(formals(my.plot), alist(... = ))
my.plot(1, 1, col='red', pch=19)
```

</details>


<details>
<summary><strong>Extra material: Infix notations</strong></summary>
Operators like `+`, `-` or `*` are using the so-called **infix** functions, where the function name is between arguments. We can define our own:

```{r infix, echo=T}
`%p%` <- function(x, y) {
paste(x,y)
}
'a' %p% 'b'
```

</details>
<!--
7. <i class="fas fa-exclamation-circle"></i> **Advanced:** At the lecture an approach to calculate factorials were implemented using recursion (function calling itself). Here we instead will have a go at generating Fibonacci numbers. A fibonacci number is part of a series of number with the following properties:
Expand Down
Loading

0 comments on commit 21134a9

Please sign in to comment.