IDEMSInternational / R-Instat

A statistics software package powered by R
http://r-instat.org/
GNU General Public License v3.0
38 stars 102 forks source link

Add a functions keyboard to the calculator #8905

Closed rdstern closed 1 month ago

rdstern commented 3 months ago

@Fidel365 I am going to take advantage that you have become very effective in improving the R-Instat calculator.

This is not ready for work yet, and I hope that @lloyddewit will also be interested. It builds on a discussion topic, #8034 plus work "completing" the complex keyboard.

It will consider functions now in 2 ways. From an R-computing perspective and also (now) from a maths perspective.

I would like to move the pascal key from probability keyboard into this keyboard. And I would like to add the polyroot function. This is in base or utils and gives the roots (maybe complex) of any polynomial. It provides a variable that is 1 value less than the number of coefficients so we give it as: c(polyroot(x1),NA). Maybe we could alternatively add 0 instead of NA? Then there is the fundamental theorem of algebra that relates the roots to the coefficients. This is provided by: sum(combn(roots, m=2,FUN=prod)) This is usually real so we just give the summary number: Re(sum(combn(roots, m=2,FUN=prod)))

we repeat sum( ), and we have omitted prod( ,na.rm=TRUE) from the summary keyboard. So we include it here. There is a summary section on this keyboard.

I would like to include minimisation of functions here too, partly because Nelder-Mead is still popular - and I knew them both well! Maybe not - there is even a neldermead package, but this could take too long!

Fidel365 commented 3 months ago

@rdstern , can I start working on this or it's not yet ready?

rdstern commented 2 months ago

Ok, I am starting it now. I suggest 4 keys across. The first row is:

ave, ave_fun, ave_fac, ave_both

The full ave function in the standard stats package is described here.

As the keys, a) ave, without parameters gives ave( ), with parameters it gives ave(x= )

b) ave_fun without parameters gives ave( , FUN=mean), with parameters it gives ave(x= ,FUN=function(x) mean(x, na.rm=TRUE))

c) ave_fun without parameters givesave( , ), with the cursor before the first comma. With parameters it is ave(x= , )

d) ave_both gives ave( , , FUN=mean) without parameters. with parameters it gives ave(x= , , FUN=function(x) mean(x, trim=0.1))

Nice and easy I hope?

Second row of keys:

ssq, ssq*, cssq, cssq*

a) ssq gives ave( , FUN= function(x) sum(x*x,na.rm=TRUE)), with parameters it just adds the x= as above. Tooltip: Gives uncorrected sum of squares through the ave function. b) ssq givesssq( )and with parameters is ssq(x= ). Tooltip : Gives uncorrected sum of squares, but only if the library calculator code has been run in the current sesion. c) cssq gives ave( ,FUN=function(x) sum((x - mean(x,na.rm=TRUE))^2,na.rm=TRUE)). Add x= if parameters. Tooltip Gives corrected sum of squares through the ave function. d) cssq gives cssq( ) and with parameters is cssq(x= ), with tooltip : Tooltip : Gives corrected sum of squares, but only if the library calculator code has been run in the current sesion. @fidel, we also have to write these functions and add them to the library. More on that later.

Third row of keys: polynom (or plynomial if there is space), orgin,roots, coeffs

a) polynomial : polynom::polynomial( ), with arguments (coef= ), tooltip Makes a variable into a polynomial object. @Fidel365 it seems to work fine, but the resulting variable should also have the name followed by (S) in the data grid. If yu have problems doing this, then check with Antoine. b) origin: polynom::change.origin( , ), with arguments (p= ,o= ) with tooltip Gives the polynomial coefficients, relative to a new origin, c) roots: c(polyroot( ),NA) and with arguments (z= ) tooltip Gives the zeros of a polynomial. d) coeffs: polynom::poly.calc( ) , with arguments (x= ) tooltip Gives the polynomial from the zeros.

Fourth row: prod, combn. coef, coeffs2

a) prod: prod( , na.rm=TRUE), with parameters prod(x= , na.rm=TRUE) with tooltip The product of the values. So prod(c(1,2,3,4,10)) = 240 b) combn: combn( , ,FUN=prod, na.rm=TRUE), with parameters combn(x- ,m- ,FUN=prod, na.rm=TRUE), tooltip: combn(c(-2,1,3,4), 2,FUN=prod) gives the products of the values 3 at a time, so (-213), (-214), (-234), (134), = -6, -12, -24, 12. (result usually put into output window) c) coef: sum(combn( , ,FUN=prod, na.rm=TRUE)) , with parameters coef: sum(combn( x= ,m= ,FUN=prod, na.rm=TRUE)) single coefficient of a polynomial if given roots. So sum(combn(c(-2,1,3,4),3. FUN=prod) =(-6 -12-24 +12) = -26 d) coeffs2: I need help from @lilyclements here! I think I need to add an sapply at the front of the key above and then give the results as a variable for m=0 to 4 (if quartic?) Now @Fidel365 see below for the code The numeric example comes from here.

Fifth row: a) Move pascal from the probability keyboard.
b) Move fractions and c) decimals from the Transform keyboard. d) dsum

dsum: sapply( ,function(n){a<-as.integer(c(strsplit(as.character(n),split="")[[1]])); sum(a)}) No difference with arguments: Tooltip Gives the sum of the digits in a numeric variable

Sixth row: dssq, dssq* (On roughly the same row as the R-help button.)

dssq: sapply( ,function(n){a<-as.integer(c(strsplit(as.character(n),split="")[[1]])); sum(a^2)}) no difference if arguments Tooltip: Gives the ssq of the digits in a numeric variable. For example with c(12, 24, 86) gives (5, 20, 100) dssq* dssq( ) or dssq(x= ) with arguments. Tooltip Gives digit sum of squares, but only if the library calculator code has been run in the current sesion.

R-Help key, so far the base MASS, polynom, stats, utils packages.

lilyclements commented 2 months ago

@rdstern I reply to your comment here:

d) coeffs2: I need help from @lilyclements here! I think I need to add an sapply at the front of the key above and then give the results as a variable for m=0 to 4 (if quartic?)

Am I understanding correctly that you would like something like this:

purrr::map_dbl(.x = 0:4, .f = ~ sum(combn(c(-2,1,3,4), .x, FUN=prod)))

this gives

1   6   3 -26 -24

Note that you can get the output as a list by using purrr::map instead: e.g., purrr::map(.x = 0:4, .f = ~ sum(combn(c(-2,1,3,4), .x, FUN=prod)))

rdstern commented 2 months ago

@lilyclements many thanks, I think that's exactly what we need! I'll check. Of course it isn't so simple for my example! quartic_equation.zip

Here is the data frame.
I also got the example wrong, it is (1,-2,3,4). In addition: a) It is in a column, where the last value is NA. That's an R-Instat limitation, because a quartic has 5 coefficients, but just 4 roots, so I need to pad the column. b) Often the roots will be complex - so the variable is complex. Hence your purrr::map.dbl complains. map works, though I would like the answers in a numeric variable if possible. Not that important. I'd prefer in a complex variable to a list and wonder if we take Re( ) that's enough. I note as.numeric works so that's a detail.

I think, also to get the coefficients in the right order, I need to change the order of the loop. So here is (I think a working, code? (data_rds is the name of the dataframe.)

purrr::map(.x=(nrow(data_RDS)-1):0, .f = ~sum(combn(rootsx3[1:nrow(data_RDS)-1], .x , FUN=prod)))

Now 2 (really small?) questions: a) I am using nrow(data_RDS)-1 twice. Can I do that bit more consisely, and/or could I define n <- nrow(data_RDS)-1 in the code and then use n? b) I don't really mind that I get a list variable at the end, though it doesn't look like my other lists, as it only has a single value. It is a list of complex values, though I think the answers are always real. So as.numeric( ) seems to work. I assume we could add that to the code.

By the way there is a function polynom::poly.calc that does it all very nicely! If I use polynom:::polycalc I can see the R code in the output window. And the comparison is what I am interested to be able to demonstrate.
a) I find it really interesting that the "Fundamental Theorem of Algebra" can be shown with this combn calculation so nicely.
b) The function does it, in an efficient, but black-box sort of way. That doesn't help understanding. c) However as a computing point, the poly.calc function demonstrates nicely the difference between writing a script and developing a bit of software. Most of the code is checkin g for oddities and that's a feature of good software.

lilyclements commented 2 months ago

@rdstern this works. What is rootsx3? I have assumed this is your 1, -2, 3, 4

Can you give an example which gives complex numbers? I'm not sure I fully follow what we're doing here.

Your suggestion does seem to work quite nicely though:

n <- nrow(data_RDS)-1
x <- as.numeric(purrr::map(.x=n:0,
           .f = ~sum(combn(rootsx3[1:n],
                           .x ,
                           FUN=prod))))
rdstern commented 2 months ago

@lilyclements thanks. I changed -24 to -10 in the sheet to get some complex roots quartic_equation (2).zip

a) In your solution it should be n:0. b) I still don't know how to do the n <- nrow(data_RDS) - 1 in the calculator? I am wondering if we could add some more objects, including scalars (and perhaps polynomials) and others to a data sheet - as more metadata? We have filters and selects already. I wonder if that would be easy, or the start of a very slippery slope. or am I stepping towards an inferior tibble?

lilyclements commented 2 months ago

@rdstern thanks.

a) Just fixed this in the code above b) Good point. You can run two bits of code in R in a single line by using the ;.

E.g.,

n <- 10; n+10

which is one solution. Otherwise, we can just have it that it is written in the R code, and not saved as n beforehand?

rdstern commented 2 months ago

Thanks @lilyclements. My problem is that the R-Instat calculator can't cope with multiple commands.

But, but, but we now have a great solution - after discussions with @volloholic we are going to add scalars to the stuff data books can store. And all just though a minor addition to the calculator. I thought that was all described in another issue, but perhaps that's my imagination!