I'm needing help with the following question:
Consider the following R function, named negloglike that has two input arguments: lam and x, in that order.
Use this function to produce a plot of the log-likelihood function over a range of values λ ∈ (0, 2).
negloglike <- function(lam, x) {
l = -sum(log(dexp(x, lam)))
return(l)
}
Can anyone please help? Is it possible to do something like this with ggplot? I've been trying to do it with a set value of lam (like 0.2 here for example) using stat_function:
ggplot(data = data.frame(x = 0), mapping = aes(x = x)) +
stat_function(fun = negloglike, args = list(lam = 0.2)) +
xlim(0,10)
but the plot always returns a horizontal line at some y-value instead of returning a curve.
Should I be possibly using a different geom? Or even a different package altogether?
Much appreciated!
The trick is to Vectorize the function over the argument of interest.
Thanks for the tip go to the most voted answer to this question. It uses base graphics only, so here is a ggplot2 equivalent.
First I will define the negative log-likelihood using function dexp
library(ggplot2)
negloglike <- function(lam, x) {negloglike <- function(lam, x) {
l = -sum(dexp(x, lam, log = TRUE))
return(l)
}
nllv <- Vectorize(negloglike, "lam")
But it's better to use the analytic form, which is easy to establish by hand.
negloglike2 <- function(lam, x) {
l = lam*sum(x) - length(x)*log(lam)
return(l)
}
nllv2 <- Vectorize(negloglike2, "lam")
ggplot(data = data.frame(lam = seq(0, 2, by = 0.2)), mapping = aes(x = lam)) +
stat_function(fun = nllv2, args = list(x = 0:10))
Both nllv and nllv2 give the same graph.
Related
I have the following equation: y = 1 - cx, where c is a real number.
I'm trying to make something where I can pick the range of values for c and plot all the graphs of every function with the corresponding c.
Here's what I got as of now:
p <- ggplot(data = data.frame(x = 0), mapping = aes(x = x))
statfun1 <- c()
for (i in 1:3){
c <- i
fun1.i <- function(x){1 - c*x}
fun1.i.plot <- stat_function(fun = fun1.i, color="red")
statfun1 <- statfun1 + fun1.i.plot
}
p + statfun1 + xlim(-5, 5)
The p is basically what you need in ggplot2 to plot a function, then I go over in this case the values 1, 2 and 3 for c and I try to add them all at the end but this does not seem to work. Anyone maybe can help me out or put me on the right track?
Define your function
fun1.i <- function(x, c){1 - c*x}
Now from ?`+.gg`
You can add any of the following types of objects:
...
You can also supply a list, in which case each element of the list will be added in turn.
So you might use lapply
p + xlim(-5, 5) + lapply(1:3, function(c) {
stat_function(fun = fun1.i, args = list(c = c), geom = "line", color="red")
})
Result
This question already has answers here:
ggplot plots in scripts do not display in Rstudio
(5 answers)
Closed 5 years ago.
I have written a function that plots (in both Base R and ggplot) the misclassification rate for various values of K in a KNN classification problem. My problem is that, while Base R plot displays, ggplot graph does not display. When I take the ggplot code out of the function, it works. I'm not sure what I am doing wrong.
Can someone please point out what I am doing wrong?
Code:
library(ISLR)
library(ggplot2)
library(class)
data("Weekly")
train <- (Weekly$Year < 2009)
Weekly.train <- Weekly[ train, ]
Weekly.test <- Weekly[ !train, ]
knn.train.x <- scale( as.data.frame(Weekly$Lag2[train]) )
knn.test.x <- scale( as.data.frame(Weekly$Lag2[!train]) )
train.Direction <- Weekly$Direction[train]
set.seed(1234)
#Function for choosing k in knn
misclassknn <- function(train, test,
response.train,
response.test,
Kmax){
K <- 1:Kmax
misclass <- numeric(Kmax)
for( k in K){
knn.pred <- knn(train,test,response.train, k=k)
misclass[k] <- mean(knn.pred!=response.test)
}
# base R
plot(c(1, Kmax), c(0, 1), type = "n",
main = "Misclassification Rate for K Values",
xlab = "K", ylab = "Misclassification Rate")
points(1 : Kmax, misclass, type = "b", pch = 16)
# ggplot
df <- data.frame(1 : Kmax, misclass)
names(df) <- c("misclass", "K")
ggplot(df, aes(x = misclass, y = K)) + geom_line() + ylim(0, 1) +
geom_point() + labs( title = "Misclassification Rate for K Values",
y = "Misclassification Rate", x = "K")
return(list(K = Kmax, misclass = misclass,
Kmin = which.min(misclass)))
}
misclassknn(train = knn.train.x,
test = knn.test.x,
response.train = train.Direction,
response.test = Weekly$Direction[!train],
Kmax = 15)
We take for granted the way plotting works in R. For ggplot it actually returns an object, which is a description for how to build plot. Inside of functions, due to the different scope things aren't displayed like they are in the global scope. Basically you either need to manually tell it to display the plot by wrapping print() or ggplot_build around the ggplot command, or you need to return the object as an output of your function and then call it from the global scope. Essentially you're just forcing it to display the object.
It's common to store the ggplot object with something like
p <- ggplot(etc) + geom_etc() + ...
Now the object p can be built into a graph when you want it to be. You could use print(p) (or ggplot_build(p)) or you could just use p in your main code if it's returned by the function, e.g. return(p).
I want to add a stat_function layer to a plot with an aesthetic mapped to the state of some variable that identifies a set of parameters. I have manually created the two stat_function lines in the minimal working example below. That's generally what the result should look like.
p <- ggplot(data.frame(x = -1:1), aes(x = x))
p + stat_function(fun = function (x) 0 + 1 * x, linetype = 'dotted') +
stat_function(fun = function (x) 0.5 + -1 * x, linetype = 'solid')
My best guess at how to accomplish this is
params <- data.frame(
type = c('true', 'estimate'),
b = c(0, 0.5),
m = c(1, -1),
x = 0
)
linear_function <- function (x, b, m) b + m * x
p + stat_function(data = params,
aes(linetype = type, x = x),
fun = linear_function,
args = list(b = b, m = m))
This form works if I use constants like args = list(b = 0, m = 1), but when I try to get the values for the parameters out of the params data frame it's unable to find those columns. Why is this not working like I expect and what's a solution?
Unfortunately, nothing positive to add here; the fact stands: stat_function does not support this functionality.
The alternative is to either use for loops to make layers, as demonstrated in this question, or generate the grid data yourself, which is what was suggested as a closing comment to a feature request discussion about adding this functionality.
I have tried to fix this problem a number of ways, but I am new to R, so I don't know the tips and tricks. I am trying to graph a polynomial function using code for a quadratic function, provided by my teacher, however, I keep running into the "unused arguments error". the issue is that I have given three arguments, which is what the function expects. this is the code I entered:
> quadratic <- function(x, u.values){
+ X <- cbind(1, x, x^2)
+ return(X %*% u.values)
+ }
> dev.new()
> ggplot() +
+ geom_point(aes(x = t,y = y),data= GData)+
+ stat_function(fun=quadratic(args=c(1.9604816, -0.1201548, -4.9768049)))
Error in quadratic(args = c(1.9604816, -0.1201548, -4.9768049)) :
unused argument(s) (args = c(1.9604816, -0.1201548, -4.9768049))
As you've defined it, quadratic doesn't have an args parameter. That's what's causing your error.
I'm guessing -- but I can't test, since your example isn't reproducible -- that you should change args in your stat_function call to something like args = list(u.values = c(1.9604816, -0.1201548, -4.9768049)).
Edit:
To clarify, args parameter of stat_function takes additional arguments to the function you specify (quadratic in this case) as a list. What you're doing is passing a named argument args to quadratic, when you want to be passing a named argument args to stat_function.
Here is a reproducible example that works:
g <- data.frame(t = seq(0.1, 1, by = 0.1), y = seq(2.1, 3, by = 0.1))
quadratic <- function(x, u.values){
X <- cbind(1, x, x^2)
return(X %*% u.values)
}
ggplot(data = g, aes(x = t, y = y)) +
geom_point() +
stat_function(fun = quadratic,
args = list(u.values = c(1.9604816, -0.1201548, -4.9768049)))
Obviously this data has nothing to do with yours, but the quadratic function is applied correctly to the data and the results are plotted.
Given family of functions f(x;q) (x is argument and q is parameter) I'd like to visulaize this function family on x taking from the interval [0,1] for 9 values of q (from 0.1 to 0.9). So far my solution is:
f = function(p,q=0.9) {1-(1-(p*q)^3)^1024}
x = seq(0.0,0.99,by=0.01)
q = seq(0.1,0.9,by=0.1)
qplot(rep(x,9), f(rep(x,9),rep(q,each=100)), colour=factor(rep(q,each=100)),
geom="line", size=I(0.9), xlab="x", ylab=expression("y=f(x)"))
I get quick and easy visual with qplot:
My concern is that this method is rather memory hungry as I need to duplicate x for each parameter and duplicate each parameter value for whole x range. What would be alternative way to produce same graph without these duplications?
At some point ggplot will need to have the data available to plot it and the way that package works prohibits simply doing what you want. I suppose you could set up a blank plot if you know the x and y axis limits, and then loop over the 9 values of q, generating the data for that q, and adding a geom_line layer to the existing plot object. However, you'll have to produce the colours for each layer yourself.
If this is representative of the size of problem you have, I wouldn't worry too much about the memory footprint. We're only talking about a two vectors of length 900
> object.size(rnorm(900))
7240 bytes
and the 100 values over the range of x appears sufficient to give a smooth plot.
for loop to add layers to ggplot
require("ggplot2")
## something to replicate ggplot's colour palette, sure there is something
## to do this already in **ggplot** now...
ggHueColours <- function(n, h = c(0, 360) + 15, l = 65, c = 100,
direction = 1, h.start = 0) {
turn <- function(x, h.start, direction) {
(x + h.start) %% 360 * direction
}
if ((diff(h) %% 360) < 1) {
h[2] <- h[2] - 360 / n
}
hcl(h = turn(seq(h[1], h[2], length = n), h.start = h.start,
direction = direction), c = c, l = l)
}
f = function(p,q=0.9) {1-(1-(p*q)^3)^1024}
x = seq(0.0,0.99,by=0.01)
q = seq(0.1,0.9,by=0.1)
cols <- ggHueColours(n = length(q))
for(i in seq_along(q)) {
df <- data.frame(y = f(x, q[i]), x = x)
if(i == 1) {
plt <- ggplot(df, aes(x = x, y = y)) + geom_line(colour = cols[i])
} else {
plt <- plt + geom_line(data = df, colour = cols[i])
}
}
plt
which gives:
I'll leave the rest to you - I'm not familiar enough with ggplot to draw a legend manually.