Defining a custom Error measure (sMAPE) function





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







0















I am defining a custom sMAPE (Symmetric Mean Absolute Percent Error) function in R. I want to add an exception in the code where both actual and predicted are zero.



Here is the sample data:



Actual   Predicted

0            0

2            1

1            0

2            4

2            1

1            3





The code is shown below:



sMAAPE <- function(actual, predicted){
if (actual == 0 & predicted == 0){
return(0)
}
else {
output<- mean(abs(actual-predicted)/(abs(actual)+abs(predicted)))
return(output)
}
}


As I mentioned, i want to add an exception, that is wherever both actual and predicted are 0, my error would be zero. The problem with my code is that, when it is encountering both actual and predicted to be 0 in first observation, it is giving the mean error to be zero, but in reality I want mean of all errors.



Can somebody help me with this?










share|improve this question


















  • 2





    Instead of if/else use ifelse with index created using rowSums ie. i1 <- !rowSums(df1 != 0); ifelse(i1, 0, othervalue) Wrap it in a function sMAAPE <- function(dat) { i1 <- !rowSums(dat !=0); val <- with(dat, mean(abs(actual-predicted)/(abs(actual)+abs(predicted)))); val[i1] <- 0; val}

    – akrun
    Jan 3 at 9:28




















0















I am defining a custom sMAPE (Symmetric Mean Absolute Percent Error) function in R. I want to add an exception in the code where both actual and predicted are zero.



Here is the sample data:



Actual   Predicted

0            0

2            1

1            0

2            4

2            1

1            3





The code is shown below:



sMAAPE <- function(actual, predicted){
if (actual == 0 & predicted == 0){
return(0)
}
else {
output<- mean(abs(actual-predicted)/(abs(actual)+abs(predicted)))
return(output)
}
}


As I mentioned, i want to add an exception, that is wherever both actual and predicted are 0, my error would be zero. The problem with my code is that, when it is encountering both actual and predicted to be 0 in first observation, it is giving the mean error to be zero, but in reality I want mean of all errors.



Can somebody help me with this?










share|improve this question


















  • 2





    Instead of if/else use ifelse with index created using rowSums ie. i1 <- !rowSums(df1 != 0); ifelse(i1, 0, othervalue) Wrap it in a function sMAAPE <- function(dat) { i1 <- !rowSums(dat !=0); val <- with(dat, mean(abs(actual-predicted)/(abs(actual)+abs(predicted)))); val[i1] <- 0; val}

    – akrun
    Jan 3 at 9:28
















0












0








0


1






I am defining a custom sMAPE (Symmetric Mean Absolute Percent Error) function in R. I want to add an exception in the code where both actual and predicted are zero.



Here is the sample data:



Actual   Predicted

0            0

2            1

1            0

2            4

2            1

1            3





The code is shown below:



sMAAPE <- function(actual, predicted){
if (actual == 0 & predicted == 0){
return(0)
}
else {
output<- mean(abs(actual-predicted)/(abs(actual)+abs(predicted)))
return(output)
}
}


As I mentioned, i want to add an exception, that is wherever both actual and predicted are 0, my error would be zero. The problem with my code is that, when it is encountering both actual and predicted to be 0 in first observation, it is giving the mean error to be zero, but in reality I want mean of all errors.



Can somebody help me with this?










share|improve this question














I am defining a custom sMAPE (Symmetric Mean Absolute Percent Error) function in R. I want to add an exception in the code where both actual and predicted are zero.



Here is the sample data:



Actual   Predicted

0            0

2            1

1            0

2            4

2            1

1            3





The code is shown below:



sMAAPE <- function(actual, predicted){
if (actual == 0 & predicted == 0){
return(0)
}
else {
output<- mean(abs(actual-predicted)/(abs(actual)+abs(predicted)))
return(output)
}
}


As I mentioned, i want to add an exception, that is wherever both actual and predicted are 0, my error would be zero. The problem with my code is that, when it is encountering both actual and predicted to be 0 in first observation, it is giving the mean error to be zero, but in reality I want mean of all errors.



Can somebody help me with this?







r






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 3 at 9:26









SourabhSourabh

93




93








  • 2





    Instead of if/else use ifelse with index created using rowSums ie. i1 <- !rowSums(df1 != 0); ifelse(i1, 0, othervalue) Wrap it in a function sMAAPE <- function(dat) { i1 <- !rowSums(dat !=0); val <- with(dat, mean(abs(actual-predicted)/(abs(actual)+abs(predicted)))); val[i1] <- 0; val}

    – akrun
    Jan 3 at 9:28
















  • 2





    Instead of if/else use ifelse with index created using rowSums ie. i1 <- !rowSums(df1 != 0); ifelse(i1, 0, othervalue) Wrap it in a function sMAAPE <- function(dat) { i1 <- !rowSums(dat !=0); val <- with(dat, mean(abs(actual-predicted)/(abs(actual)+abs(predicted)))); val[i1] <- 0; val}

    – akrun
    Jan 3 at 9:28










2




2





Instead of if/else use ifelse with index created using rowSums ie. i1 <- !rowSums(df1 != 0); ifelse(i1, 0, othervalue) Wrap it in a function sMAAPE <- function(dat) { i1 <- !rowSums(dat !=0); val <- with(dat, mean(abs(actual-predicted)/(abs(actual)+abs(predicted)))); val[i1] <- 0; val}

– akrun
Jan 3 at 9:28







Instead of if/else use ifelse with index created using rowSums ie. i1 <- !rowSums(df1 != 0); ifelse(i1, 0, othervalue) Wrap it in a function sMAAPE <- function(dat) { i1 <- !rowSums(dat !=0); val <- with(dat, mean(abs(actual-predicted)/(abs(actual)+abs(predicted)))); val[i1] <- 0; val}

– akrun
Jan 3 at 9:28














2 Answers
2






active

oldest

votes


















1














Applying @akrun's suggestion in the comments to your problem. I think this is what you need.



# Create a dataset    
Actual <- c(0,2,1,2,2,1)
Predicted <- c(0,1,0,4,1,3)
df <- data.frame(cbind(Actual, Predicted))
df


sMAAPE <- function(actual, predicted){
output<- ifelse(actual == 0 & predicted == 0,0, # If actual and predicted are 0, error is 0
abs(actual- predicted)/(abs(actual)+abs(predicted))) # otherwise your function
return(mean(output)) # Return mean of all errors
}


The output:



> sMAAPE(df$Actual, df$Predicted)
[1] 0.4166667


Which is the mean of the following vector [1] 0 0.3333333 1.0000000 0.3333333 0.3333333 0.5000000



You could add na.rm = T to the mean function so it handles NA's as well.






share|improve this answer


























  • This is also working. Also, if we add na.rm = T in mean function, this will not consider those NA's at all, therefore the mean would be wrong as the length of df will change after excluding NA's. To deal with this, I used na.rm = T is sum function and then diving this sum with length of dataframe.

    – Sourabh
    Jan 4 at 11:48













  • Adding to my previous comment, Here is the code: output_sum<- sum(abs(actual-predicted)/(abs(actual)+abs(predicted)), na.rm = T) output <- output_sum/NROW(actual) return(output)

    – Sourabh
    Jan 4 at 11:57





















0














The problem is that actual == 0 & predicted == 0 is a logical vector, while if you put a logical vector as the condition of if sentence, only the first element will be judged.



Use sum(abs(actual))+sum(abs(predicted)) == 0 instead in the condition.






share|improve this answer
























  • This worked. Using sum function allows R to go the else condition. Thanks

    – Sourabh
    Jan 4 at 11:47












Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54019430%2fdefining-a-custom-error-measure-smape-function%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














Applying @akrun's suggestion in the comments to your problem. I think this is what you need.



# Create a dataset    
Actual <- c(0,2,1,2,2,1)
Predicted <- c(0,1,0,4,1,3)
df <- data.frame(cbind(Actual, Predicted))
df


sMAAPE <- function(actual, predicted){
output<- ifelse(actual == 0 & predicted == 0,0, # If actual and predicted are 0, error is 0
abs(actual- predicted)/(abs(actual)+abs(predicted))) # otherwise your function
return(mean(output)) # Return mean of all errors
}


The output:



> sMAAPE(df$Actual, df$Predicted)
[1] 0.4166667


Which is the mean of the following vector [1] 0 0.3333333 1.0000000 0.3333333 0.3333333 0.5000000



You could add na.rm = T to the mean function so it handles NA's as well.






share|improve this answer


























  • This is also working. Also, if we add na.rm = T in mean function, this will not consider those NA's at all, therefore the mean would be wrong as the length of df will change after excluding NA's. To deal with this, I used na.rm = T is sum function and then diving this sum with length of dataframe.

    – Sourabh
    Jan 4 at 11:48













  • Adding to my previous comment, Here is the code: output_sum<- sum(abs(actual-predicted)/(abs(actual)+abs(predicted)), na.rm = T) output <- output_sum/NROW(actual) return(output)

    – Sourabh
    Jan 4 at 11:57


















1














Applying @akrun's suggestion in the comments to your problem. I think this is what you need.



# Create a dataset    
Actual <- c(0,2,1,2,2,1)
Predicted <- c(0,1,0,4,1,3)
df <- data.frame(cbind(Actual, Predicted))
df


sMAAPE <- function(actual, predicted){
output<- ifelse(actual == 0 & predicted == 0,0, # If actual and predicted are 0, error is 0
abs(actual- predicted)/(abs(actual)+abs(predicted))) # otherwise your function
return(mean(output)) # Return mean of all errors
}


The output:



> sMAAPE(df$Actual, df$Predicted)
[1] 0.4166667


Which is the mean of the following vector [1] 0 0.3333333 1.0000000 0.3333333 0.3333333 0.5000000



You could add na.rm = T to the mean function so it handles NA's as well.






share|improve this answer


























  • This is also working. Also, if we add na.rm = T in mean function, this will not consider those NA's at all, therefore the mean would be wrong as the length of df will change after excluding NA's. To deal with this, I used na.rm = T is sum function and then diving this sum with length of dataframe.

    – Sourabh
    Jan 4 at 11:48













  • Adding to my previous comment, Here is the code: output_sum<- sum(abs(actual-predicted)/(abs(actual)+abs(predicted)), na.rm = T) output <- output_sum/NROW(actual) return(output)

    – Sourabh
    Jan 4 at 11:57
















1












1








1







Applying @akrun's suggestion in the comments to your problem. I think this is what you need.



# Create a dataset    
Actual <- c(0,2,1,2,2,1)
Predicted <- c(0,1,0,4,1,3)
df <- data.frame(cbind(Actual, Predicted))
df


sMAAPE <- function(actual, predicted){
output<- ifelse(actual == 0 & predicted == 0,0, # If actual and predicted are 0, error is 0
abs(actual- predicted)/(abs(actual)+abs(predicted))) # otherwise your function
return(mean(output)) # Return mean of all errors
}


The output:



> sMAAPE(df$Actual, df$Predicted)
[1] 0.4166667


Which is the mean of the following vector [1] 0 0.3333333 1.0000000 0.3333333 0.3333333 0.5000000



You could add na.rm = T to the mean function so it handles NA's as well.






share|improve this answer















Applying @akrun's suggestion in the comments to your problem. I think this is what you need.



# Create a dataset    
Actual <- c(0,2,1,2,2,1)
Predicted <- c(0,1,0,4,1,3)
df <- data.frame(cbind(Actual, Predicted))
df


sMAAPE <- function(actual, predicted){
output<- ifelse(actual == 0 & predicted == 0,0, # If actual and predicted are 0, error is 0
abs(actual- predicted)/(abs(actual)+abs(predicted))) # otherwise your function
return(mean(output)) # Return mean of all errors
}


The output:



> sMAAPE(df$Actual, df$Predicted)
[1] 0.4166667


Which is the mean of the following vector [1] 0 0.3333333 1.0000000 0.3333333 0.3333333 0.5000000



You could add na.rm = T to the mean function so it handles NA's as well.







share|improve this answer














share|improve this answer



share|improve this answer








edited Jan 3 at 10:29

























answered Jan 3 at 10:22









NiekNiek

974518




974518













  • This is also working. Also, if we add na.rm = T in mean function, this will not consider those NA's at all, therefore the mean would be wrong as the length of df will change after excluding NA's. To deal with this, I used na.rm = T is sum function and then diving this sum with length of dataframe.

    – Sourabh
    Jan 4 at 11:48













  • Adding to my previous comment, Here is the code: output_sum<- sum(abs(actual-predicted)/(abs(actual)+abs(predicted)), na.rm = T) output <- output_sum/NROW(actual) return(output)

    – Sourabh
    Jan 4 at 11:57





















  • This is also working. Also, if we add na.rm = T in mean function, this will not consider those NA's at all, therefore the mean would be wrong as the length of df will change after excluding NA's. To deal with this, I used na.rm = T is sum function and then diving this sum with length of dataframe.

    – Sourabh
    Jan 4 at 11:48













  • Adding to my previous comment, Here is the code: output_sum<- sum(abs(actual-predicted)/(abs(actual)+abs(predicted)), na.rm = T) output <- output_sum/NROW(actual) return(output)

    – Sourabh
    Jan 4 at 11:57



















This is also working. Also, if we add na.rm = T in mean function, this will not consider those NA's at all, therefore the mean would be wrong as the length of df will change after excluding NA's. To deal with this, I used na.rm = T is sum function and then diving this sum with length of dataframe.

– Sourabh
Jan 4 at 11:48







This is also working. Also, if we add na.rm = T in mean function, this will not consider those NA's at all, therefore the mean would be wrong as the length of df will change after excluding NA's. To deal with this, I used na.rm = T is sum function and then diving this sum with length of dataframe.

– Sourabh
Jan 4 at 11:48















Adding to my previous comment, Here is the code: output_sum<- sum(abs(actual-predicted)/(abs(actual)+abs(predicted)), na.rm = T) output <- output_sum/NROW(actual) return(output)

– Sourabh
Jan 4 at 11:57







Adding to my previous comment, Here is the code: output_sum<- sum(abs(actual-predicted)/(abs(actual)+abs(predicted)), na.rm = T) output <- output_sum/NROW(actual) return(output)

– Sourabh
Jan 4 at 11:57















0














The problem is that actual == 0 & predicted == 0 is a logical vector, while if you put a logical vector as the condition of if sentence, only the first element will be judged.



Use sum(abs(actual))+sum(abs(predicted)) == 0 instead in the condition.






share|improve this answer
























  • This worked. Using sum function allows R to go the else condition. Thanks

    – Sourabh
    Jan 4 at 11:47
















0














The problem is that actual == 0 & predicted == 0 is a logical vector, while if you put a logical vector as the condition of if sentence, only the first element will be judged.



Use sum(abs(actual))+sum(abs(predicted)) == 0 instead in the condition.






share|improve this answer
























  • This worked. Using sum function allows R to go the else condition. Thanks

    – Sourabh
    Jan 4 at 11:47














0












0








0







The problem is that actual == 0 & predicted == 0 is a logical vector, while if you put a logical vector as the condition of if sentence, only the first element will be judged.



Use sum(abs(actual))+sum(abs(predicted)) == 0 instead in the condition.






share|improve this answer













The problem is that actual == 0 & predicted == 0 is a logical vector, while if you put a logical vector as the condition of if sentence, only the first element will be judged.



Use sum(abs(actual))+sum(abs(predicted)) == 0 instead in the condition.







share|improve this answer












share|improve this answer



share|improve this answer










answered Jan 3 at 9:43









XinzXinz

543




543













  • This worked. Using sum function allows R to go the else condition. Thanks

    – Sourabh
    Jan 4 at 11:47



















  • This worked. Using sum function allows R to go the else condition. Thanks

    – Sourabh
    Jan 4 at 11:47

















This worked. Using sum function allows R to go the else condition. Thanks

– Sourabh
Jan 4 at 11:47





This worked. Using sum function allows R to go the else condition. Thanks

– Sourabh
Jan 4 at 11:47


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54019430%2fdefining-a-custom-error-measure-smape-function%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

MongoDB - Not Authorized To Execute Command

in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith

How to fix TextFormField cause rebuild widget in Flutter