I'm trying to round random grades (vector) to the nearest grade (category) with for and if loop. The idea is that the function takes the grades and puts them into a category. The category holds the rounded grades and has the variable 'gradesRounded'. gradesRounded will be returned and printed and this is giving logical(0) as output. I would very much like for a vector containing the rounded grades to be the output. How do I fix this? (input/output should be vectors and function name + return(gradesRounded must include due to it being assignment-related) output should be -3, 7, 4, 12, -3
roundGrade <- function(grades) {
grades <- c(-3, 7, 3, 11, -2)
gradesRounded <- category
for (i in grades){
if (grades >= -3 & grades <= -2) {category=("-3")}
else if (grades >= -2 & grades <= 00) {category=("00")}
else if (grades >= 1 & grades <= 02) {category=("02")}
else if (grades >= 3 & grades <= 4) {category=("4")}
else if (grades >= 6 & grades <= 7) {category=("7")}
else if (grades >= 8 & grades <= 10) {category=("10")}
else if (grades >= 11 & grades <= 12) {category=("12")}
return(gradesRounded)
}
}
You probably were trying to do :
roundGrade <- function(grades) {
category <- numeric(length(grades))
for (i in seq_along(grades)) {
if (grades[i] >= -3 & grades[i] <= -2) {category[i]= -3}
else if (grades[i] >= -2 & grades[i] <= 0) {category[i]= 0}
else if (grades[i] >= 1 & grades[i] <= 2) {category[i]= 2}
else if (grades[i] >= 3 & grades[i] <= 4) {category[i]= 4}
else if (grades[i] >= 6 & grades[i] <= 7) {category[i]= 7}
else if (grades[i] >= 8 & grades[i] <= 10) {category[i]= 10}
else if (grades[i] >= 11 & grades[i] <= 12) {category[i]= 12}
}
return(category)
}
grades <- c(-3, 7, 3, 11, -2)
result <- roundGrade(grades)
result
#[1] -3 7 4 12 -3
Also have a look at ?cut and ?findInterval which is helpful for such cases.
Related
I am new to R shiny and am trying to make a diet calculator (assuming you have isotope values for 15N and 13C measurements for your fingernail/hair samples). I am having trouble formatting my if statement to produce my output statement that gives you a diet based on the d13C and d15N inputs (i.e., if values d15Nair = 6, d13Cpdb = -24...... "your diet primarily consists of fruit, vegetables, and grain eaters").
It seems to me that this strictly a formatting issue, I would appreciate any feedback.
library(shiny)
library(tidyverse)
ui <- fluidPage(numericInput(inputId = "Cnumber",
label = "d13C (per mil)",
value = "2",),
numericInput(inputId = "Nnumber",
label = "d15N (per mil)",
value = "1"),
textOutput(outputId = "DietCalculator")
)
server <- function(input, output, session) {
d13Cpdb <- reactive(input$Cnumber)
d15Nair <- reactive(input$Nnumber)
}
if(d13Cpdb <= -23 & d13Cpdb >= -29 & d15Nair <= 7 & d15Nair >= -1)
{print("Fruits, Vegetables, and Grain eaters")
} else if(d13Cpdb <= -22 & d13Cpdb >= -29 & d15Nair <= 11 & d15Nair >= -7)
{print("Non-corn-Fed Meat Consumers")
} else if(d13Cpdb <= -17 & d13Cpdb >= -19 & d15Nair <= 6 & d15Nair >= 4)
{print("Dairy Consumers")
} else if(d13Cpdb <= -21 & d13Cpdb >= -18 & d15Nair <= 17 & d15Nair >= 12)
{print("Marine Fish Consumers")
} else if(d13Cpdb <= -12 & d13Cpdb >= -17 & d15Nair <= 11 & d15Nair >= 3)
{print("Corn-Fed Meat Consumers")
} else if(d13Cpdb <= -10 & d13Cpdb >= -13 & d15Nair <= 5 & d15Nair >= 3)
{print("Corn & Sugar Cane Product Consumers, eat healthier")
} else {(print("Diverse diets incorporating more than one source"))
}
output$DietCalculator <- renderText({input$Cnumber})
output$DietCalculator <- renderText({input$Nnumber})
shinyApp(ui = ui, server = server)
As #YBS mentioned, as d13Cpdb is a reactive, you need to change the code to be d13Cpdb(). The second thing I did was move the end bracket of server<-function(input, output, session){ } to encompass the output$DietCalculator. Also noteworthy that you have two different renderText() codes going to the same output$DietCalculator. If you wanted to display both, then you would need to make a second output of a different name, or perhaps if you wanted them both in one output, use a paste function, something like paste0("Cnumber is ", input$Cnumber," and Nnumber is ", input$Nnumber). Lastly, I was thinking you wanted your if statement to display in the renderText(), so I moved that into the renderText(), and removed all of the print() functions. This way it would put it in the shiny app. Hopefully this is about what you were looking for. Best of luck in your future endeavors!
library(shiny)
library(tidyverse)
ui <- fluidPage(numericInput(inputId = "Cnumber",
label = "d13C (per mil)",
value = "2",),
numericInput(inputId = "Nnumber",
label = "d15N (per mil)",
value = "1"),
textOutput(outputId = "DietCalculator")
)
server <- function(input, output, session) {
d13Cpdb <- reactive(input$Cnumber)
d15Nair <- reactive(input$Nnumber)
output$DietCalculator <- renderText({
req(input$Cnumber, input$Nnumber)
if(d13Cpdb() <= -23 & d13Cpdb() >= -29 & d15Nair() <= 7 & d15Nair() >= -1)
{"Fruits, Vegetables, and Grain eaters"
} else if(d13Cpdb() <= -22 & d13Cpdb() >= -29 & d15Nair() <= 11 & d15Nair() >= -7)
{"Non-corn-Fed Meat Consumers"
} else if(d13Cpdb() <= -17 & d13Cpdb() >= -19 & d15Nair() <= 6 & d15Nair() >= 4)
{"Dairy Consumers"
} else if(d13Cpdb() <= -21 & d13Cpdb() >= -18 & d15Nair() <= 17 & d15Nair() >= 12)
{"Marine Fish Consumers"
} else if(d13Cpdb() <= -12 & d13Cpdb() >= -17 & d15Nair() <= 11 & d15Nair() >= 3)
{"Corn-Fed Meat Consumers"
} else if(d13Cpdb() <= -10 & d13Cpdb() >= -13 & d15Nair() <= 5 & d15Nair() >= 3)
{"Corn & Sugar Cane Product Consumers, eat healthier"
} else {"Diverse diets incorporating more than one source"
}
})
}
shinyApp(ui = ui, server = server)
I have this formula in R, i want to be able to apply it to a different number of value without rewriting it again. e.g: 6 price comparisons instead of 4. How can i do that?
i have been doing is this way, but when i want to compare to different lags and leads, I have to rewrite it
a<- for (i in price [sP+1]:length(price)){
if (price[i] < price[i-1] & price[i] < price[i-2] &
price[i] < price[i-3] & price[i] < price[i-4] &
price[i] < price[i+1] & price[i] < price[i+2] &
price[i] < price[i+3] & price[i] < price[i+4])
}
You could check the differences around price[i]. e.g.
price <- c(27, 30, 4, 13, 2, 19, 25, 28, 26, 8)
# Say you want to check around i=5:
lo <- price[5] - price[1:4]
-25 -28 -2 -11
hi <- price[5] - price[6:9]
-17 -23 -26 -24
both <- c(lo, hi)
all(both < 0)
TRUE
You could wrap that in a function that passes the price vector, the target price index number and the lo/hi ranges as parameters, then return the output from the all function.
I am trying to check numbers in three columns in a data frame and if they're within a certain range, I want a certain output. I have this part of the code, but one of my tests wants to know if all three are negative, then I get a certain output. My issue is that some of the data in some of the columns are NA. I want to ignore the NAs in my logic. Is there a way to do this? A sample of my code is below.
if((DataWSGR$RouteType == 7 | DataWSGR$RouteType == 9) & (DataWSGR$SGR > 5 ) & (0 < DataWSGR$`30_Year_SGR` < 5) & (0 < DataWSGR$`20_Year_SGR` < 5) & (0 < DataWSGR$`10_Year_SGR` < 5)) {}
The 10, 20, and 30 year SGRs are the columns that will have NAs in them.
After fixing the range condition, I think you can just add | is.na(var) to the last three conditions:
if ((DataWSGR$RouteType == 7 |
DataWSGR$RouteType == 9)) &
(DataWSGR$SGR > 5) &
(DataWSGR$`30_Year_SGR` > 0 & DataWSGR$`30_Year_SGR` < 5 | is.na(DataWSGR$`30_Year_SGR`)) &
(DataWSGR$`20_Year_SGR` > 0 & DataWSGR$`20_Year_SGR` < 5 | is.na(DataWSGR$`20_Year_SGR`)) &
(DataWSGR$`10_Year_SGR` > 0 & DataWSGR$`10_Year_SGR` < 5 | is.na(DataWSGR$`10_Year_SGR`))) {
}
If DataWSGR has more than one row, the above will throw an error.
Here is a reproducible example for doing this in a for loop:
df <- data.frame(
route_type = c(7, 6, 9),
sgr = c(6, 3, 6),
sgr_30 = c(3, 1, NA),
sgr_20 = c(1, 1, NA),
sgr_10 = c(2, 1, NA)
)
for (i in 1:nrow(df)) {
if (
(df$route_type[i] == 7 | df$route_type[i] == 9) &
(df$sgr[i] > 5) &
(df$sgr_30[1] > 0 & df$sgr_30[i] < 5 | is.na(df$sgr_30[i])) &
(df$sgr_20[1] > 0 & df$sgr_20[i] < 5 | is.na(df$sgr_20[i])) &
(df$sgr_10[1] > 0 & df$sgr_10[i] < 5 | is.na(df$sgr_10[i]))
) {
print(paste("In range in row", i))
}
}
I have a problem with a school task -> BMI calculator
Here is my code:
#Przedziały
niedowaga <- seq(16.00, 18.40, 0.01)
norma <- seq(18.50, 24.90, 0.01)
nadwaga <- seq(25.00, 30.00, 0.01)
print(niedowaga)
print(norma)
print(nadwaga)
#Pytanie
waga = as.integer(readline(prompt="Podaj swoją wagę: "))
wzrost = as.integer(readline(prompt="Podaj swój wzrost w cm: "))
#Formuła
bmi <- waga/wzrost**2 * 10000
#Zaokrąglenie BMI do jednej liczby po przecinku
bmi_round <-round(bmi, digits = 2)
#Wyświetlenie wartości BMI po zaokrągleniu
print(bmi_round)
#Sprawdzenie BMI w oparciu o przedziały
for(bmi_round in niedowaga) {
if(bmi == niedowaga) {
print("Niedowaga")
}
}
else {
if (bmi == norma) {
print("Norma")
}
}
else if (bmi == nadwaga) {
print("Nadwaga")
}
I have three sequence variables, "niedowaga, norma, and nadwaga"
I calculated the BMI index.
Now I need to make a loop to check the computed BMI. "bmi_round" have to check to which sequence it fits - "niedowaga", "norma" and "nadwaga" (the first three variables) and give the output based on the computed BMI and sequence-
How can I do this?
Sorry for language in comments and in variables name - it's polish ;)
A loop is not needed for this:
waga = 30L #changed from readline
wzrost = 60L #changed from readline
bmi <- waga/wzrost**2 * 10000
ifelse(bmi >= 16 & bmi < 18.5, 'Niedowaga',
ifelse(bmi >= 18.5 & bmi < 25, 'Norma',
ifelse(bmi >=25 & bmi <= 30, 'nadwaga', 'outside normal range')))
# or
dplyr::case_when(bmi >= 16 & bmi < 18.5 ~ 'Niedowaga',
bmi >= 18.5 & bmi < 25 ~ 'Norma',
bmi >=25 & bmi <= 30 ~ 'nadwaga',
TRUE ~ 'outside normal range')
For your loop, there are overall errors. It appears that you are trying to compare the bmi_round variable with everything else. Instead, your loop isn't really doing anything - bmi_round is changing to each element of niedowaga in the loop and is not being used. Here is one way to change it
bmi_round <- 23
for(nied in niedowaga){
if (bmi_round == nied) print("Niedowaga")
}
for (norm in norma){
if (bmi_round == norm) print("Norma")
}
# [1] "Norma"
for (nad in nadwaga){
if (bmi_round == norm) print("Nadwaga")
}
I am having trouble again with my code. Here is the question and what I have right now:
# 2. Draw a random sample of size n=20 from a uniform distribution in 0 and 1 using
# runif(20). Sequentially, print values using the following rules:
# i. Print a value if it is less than 0.3 or more than 0.8, but skip it
# (don’t print the value) if it is in (0.1, 0.2],
# ii. Skip the entire process if you find a value in [0.4,0.5].
# Write three separate R codes using (a) for loop, (b) while loop
# and (c) repeat loop.
# (a) for loop
n = runif(20)
for (val in n){
if (val > 0.1 & val <= 0.2){
next
} else if (val < 0.3 | val > 0.8){
print(val)
} else if (val >= 0.4 & val <= 0.5){
print(val)
break
}
}
# (b) while loop
n = 1
m = runif(20)
while(n < 20){
if (m > 0.1 & m <= 0.2){
next
} else if (m < 0.3 | m > 0.8){
print(m)
} else if (m >= 0.4 & m <= 0.5){
print(m)
break
}
n = n + 1
}
# (c) repeat loop
n = 1
m = runif(20)
repeat{
if (m > 0.1 & m <= 0.2){
next
} else if (m < 0.3 | m > 0.8){
print(val)
} else if (m >= 0.4 & m <= 0.5){
print(m)
break
}
}
Part (a) for loop is working perfectly.
My only issue is (b) while loop and (c) repeat loop. He didn't do a good job in class or notes going over a while loop and repeat loop. Please help.
The object m that you created has a length of 20, so when you go to test it with something like if (m > 0.1 & m <= 0.2), R only tests the first item in your object. To solve this, you'll need to index m with n, your loop counter. In other words, don't use m in your tests, but use m[n] instead. In all it should look like this:
n <- 1
m <- runif(20)
while(n < 20){
if (m[n] > 0.1 & m[n] <= 0.2){
next
} else if (m[n] < 0.3 | m[n] > 0.8){
print(m[n])
} else if (m[n] >= 0.4 & m[n] <= 0.5){
print(m[n])
break
}
n <- n + 1
}
You should be able to use a similar approach for part c. (Also note that in part c you have print(val) at one point.)
Hope that helps!
Apparently the exercise if for you to sort it out, but OK, I'll post a solution.
# (b) while loop
n = 1
m = runif(20)
while(n <= 20){
if (m[n] > 0.1 & m[n] <= 0.2){
n = n + 1
next
} else if (m[n] < 0.3 | m[n] > 0.8){
print(m[n])
} else if (m[n] >= 0.4 & m[n] <= 0.5){
print(m[n])
break
}
n = n + 1
}
# (c) repeat loop
n = 0
m = runif(20)
repeat{
if(n < 20)
n <- n + 1
else
break
if (m[n] > 0.1 & m[n] <= 0.2){
next
} else if (m[n] < 0.3 | m[n] > 0.8){
print(m[n])
} else if (m[n] >= 0.4 & m[n] <= 0.5){
print(m[n])
break
}
}
As a final note, whenever pseudo-random number generators are used you should set the initial value in order for the results to be reproducible. This is done like this:
set.seed(6019) # or any other value, 6019 is the seed
This is put before the first call to runif.