Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A general question on Treat data with customized function #64

Open
liuyanguu opened this issue Oct 7, 2024 · 5 comments
Open

A general question on Treat data with customized function #64

liuyanguu opened this issue Oct 7, 2024 · 5 comments

Comments

@liuyanguu
Copy link

I'm sorry for the multiple questions. I have a quick question: all my indicators are percentages and I want to apply a simple function like below to all indicators, is it possible to use the "Treat" function for it?

f_custom <- function(x, direction) {
  if (direction == -1) {
    return(1 - x)
  } else {
    return(x) # Identity transformation if direction is 1
  }
}

basically return the same value if direction is 1 and (1 - x) if the direction is -1.

I tried

LCI_imp <- Treat(LCI_imp, dset = "Imputed", 
                     global_specs = list(f_n = "f_custom", f_n_para = "use_iMeta"))

but nothing changes and all values remain the same? Sorry I haven't figured out the right way to do it...

Thank you so much for your help. Much appreciated!

@bluefoxr
Copy link
Owner

bluefoxr commented Oct 8, 2024

If you're trying to flip the directions of indicators, you probably want to use the Normalise() function, which does that automatically for you based on the directions specified in iMeta. It also lets you pass custom functions to it. You can also do a completely custom operation using the Custom() function if you can't do it another way.

@liuyanguu
Copy link
Author

liuyanguu commented Oct 8, 2024

Many thanks for your prompt reply. I have tried Normalise and encounter the same issue.
Unfortunately setting global = FALSE is not enough for custom function

library("COINr")
n_f_custom <- function(x, direction) {
  if (direction == -1) {
    return(1 - x)
  } else {
    return(x) # Identity transformation if direction is 1
  }
}
purse <- build_example_purse(up_to = "new_coin")
purse <- Normalise(purse, dset = "Raw", global_specs = list(f_n = "f_custom", f_n_para = "use_iMeta"), global = FALSE)

reports "Error in get_iMeta_norm_paras(coin, func_name = global_specs[["f_n"]]) :
Your normalisation function 'f_custom' does not have support for iMeta parameters."

I have also tried Custom, but it seems it cannot use iMeta.

purse <- build_example_purse(up_to = "new_coin")
purse <- Custom(purse, dset = "Raw", f_cust = f_custom, f_cust_para = "use_iMeta")

Update: I managed to get

purse <- Normalise(purse, dset = "Raw", global_specs = list(f_n = "f_custom", f_n_para = "use_iMeta"), global = FALSE)

work by modifying the get_iMeta_norm_paras function, adding the following lines:

required_cols <- switch(
    func_name,
    n_f_custom = c("Direction"),
...)

# add `drop = FALSE` since I only have one argument
      paras <- iMeta[iMeta$iCode == names(l_n)[ii], required_cols, drop = FALSE] # drop = FALSE to keep as data frame

# add to list component
    l$f_n_para <- switch(
      func_name,
      n_f_custom = list(direction = paras$Direction),
...)

@bluefoxr
Copy link
Owner

bluefoxr commented Oct 9, 2024

@liuyanguu have you looked at the documentation on normalisation at https://bluefoxr.github.io/COINr/articles/normalise.html#coins

As far as I can tell you just want to flip the indicator directions, and this is taken care of by Normalise() without needing to pass your function to it. Normally the reversal of directions is done at the normalisation step, in addition to another scaling operation such as min-max. All of this is built into the package. Also please check the function documentation - if a function doesn't explicitly say it can access iMeta then it can't, these are special cases, again it is written out in the documentation.

@liuyanguu
Copy link
Author

liuyanguu commented Oct 11, 2024

Dear @bluefoxr, I have read all the documentation. Indeed, what I am doing is very simple, but I am not only flipping the indicator direction — I am keeping the same value if it is a positive indicator and calculating (1 - x) if it is a negative indicator. And I'd like to use f_n_para = use_iMeta. I see no other way to get Normalise work with a custom function (which pulls information from iMeta) without modifying the get_iMeta_norm_paras function.

purse <- Normalise(purse, dset = "Raw", global_specs = list(f_n = "f_custom", f_n_para = "use_iMeta"), global = FALSE)

@bluefoxr
Copy link
Owner

I think then maybe the answer is a Custom operation, passing the iMeta data frame "manually" (or just the direction and iCode columns) to the f_cust_para argument.

In Custom.purse() the operation happens like this:

# run global dset through function
iDatas_c <- do.call(f_cust, c(list(x = iDatas), f_cust_para))

So if you make a function like your one above, where it looks up the direction for each column, it should do the trick.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants