ref #65, new formula functions: PEARSON and RSQ

pull/2/head
xuri 3 years ago
parent c0d341706d
commit 66776730b6
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7

@ -584,6 +584,7 @@ type formulaFuncs struct {
// ODDFPRICE // ODDFPRICE
// OR // OR
// PDURATION // PDURATION
// PEARSON
// PERCENTILE.EXC // PERCENTILE.EXC
// PERCENTILE.INC // PERCENTILE.INC
// PERCENTILE // PERCENTILE
@ -628,6 +629,7 @@ type formulaFuncs struct {
// ROW // ROW
// ROWS // ROWS
// RRI // RRI
// RSQ
// SEC // SEC
// SECH // SECH
// SECOND // SECOND
@ -8858,6 +8860,56 @@ func (fn *formulaFuncs) min(mina bool, argsList *list.List) formulaArg {
return newNumberFormulaArg(min) return newNumberFormulaArg(min)
} }
// pearsonProduct is an implementation of the formula functions PEARSON and
// RSQ.
func (fn *formulaFuncs) pearsonProduct(name string, argsList *list.List) formulaArg {
if argsList.Len() != 2 {
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 2 arguments", name))
}
array1 := argsList.Front().Value.(formulaArg).ToList()
array2 := argsList.Back().Value.(formulaArg).ToList()
if len(array1) != len(array2) {
return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
}
var sum, deltaX, deltaY, x, y, length float64
for i := 0; i < len(array1); i++ {
num1, num2 := array1[i].ToNumber(), array2[i].ToNumber()
if !(num1.Type == ArgNumber && num2.Type == ArgNumber) {
continue
}
x += num1.Number
y += num2.Number
length++
}
x /= length
y /= length
for i := 0; i < len(array1); i++ {
num1, num2 := array1[i].ToNumber(), array2[i].ToNumber()
if !(num1.Type == ArgNumber && num2.Type == ArgNumber) {
continue
}
sum += (num1.Number - x) * (num2.Number - y)
deltaX += (num1.Number - x) * (num1.Number - x)
deltaY += (num2.Number - y) * (num2.Number - y)
}
if deltaX == 0 || deltaY == 0 {
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
}
if name == "RSQ" {
return newNumberFormulaArg(math.Pow(sum/math.Sqrt(deltaX*deltaY), 2))
}
return newNumberFormulaArg(sum / math.Sqrt(deltaX*deltaY))
}
// PEARSON function calculates the Pearson Product-Moment Correlation
// Coefficient for two sets of values. The syntax of the function is:
//
// PEARSON(array1,array2)
//
func (fn *formulaFuncs) PEARSON(argsList *list.List) formulaArg {
return fn.pearsonProduct("PEARSON", argsList)
}
// PERCENTILEdotEXC function returns the k'th percentile (i.e. the value below // PERCENTILEdotEXC function returns the k'th percentile (i.e. the value below
// which k% of the data values fall) for a supplied range of values and a // which k% of the data values fall) for a supplied range of values and a
// supplied k (between 0 & 1 exclusive).The syntax of the function is: // supplied k (between 0 & 1 exclusive).The syntax of the function is:
@ -9206,6 +9258,16 @@ func (fn *formulaFuncs) RANK(argsList *list.List) formulaArg {
return fn.rank("RANK", argsList) return fn.rank("RANK", argsList)
} }
// RSQ function calculates the square of the Pearson Product-Moment Correlation
// Coefficient for two supplied sets of values. The syntax of the function
// is:
//
// RSQ(known_y's,known_x's)
//
func (fn *formulaFuncs) RSQ(argsList *list.List) formulaArg {
return fn.pearsonProduct("RSQ", argsList)
}
// SKEW function calculates the skewness of the distribution of a supplied set // SKEW function calculates the skewness of the distribution of a supplied set
// of values. The syntax of the function is: // of values. The syntax of the function is:
// //

@ -1095,6 +1095,8 @@ func TestCalcCellValue(t *testing.T) {
"=MINA(A1:B4,MUNIT(1),INT(0),1,E1:F2,\"\")": "0", "=MINA(A1:B4,MUNIT(1),INT(0),1,E1:F2,\"\")": "0",
// MINIFS // MINIFS
"=MINIFS(F2:F4,A2:A4,\">0\")": "22100", "=MINIFS(F2:F4,A2:A4,\">0\")": "22100",
// PEARSON
"=PEARSON(A1:A4,B1:B4)": "1",
// PERCENTILE.EXC // PERCENTILE.EXC
"=PERCENTILE.EXC(A1:A4,0.2)": "0", "=PERCENTILE.EXC(A1:A4,0.2)": "0",
"=PERCENTILE.EXC(A1:A4,0.6)": "2", "=PERCENTILE.EXC(A1:A4,0.6)": "2",
@ -1149,6 +1151,8 @@ func TestCalcCellValue(t *testing.T) {
"=RANK.EQ(1,A1:B5)": "5", "=RANK.EQ(1,A1:B5)": "5",
"=RANK.EQ(1,A1:B5,0)": "5", "=RANK.EQ(1,A1:B5,0)": "5",
"=RANK.EQ(1,A1:B5,1)": "2", "=RANK.EQ(1,A1:B5,1)": "2",
// RSQ
"=RSQ(A1:A4,B1:B4)": "1",
// SKEW // SKEW
"=SKEW(1,2,3,4,3)": "-0.404796008910937", "=SKEW(1,2,3,4,3)": "-0.404796008910937",
"=SKEW(A1:B2)": "0", "=SKEW(A1:B2)": "0",
@ -2974,6 +2978,10 @@ func TestCalcCellValue(t *testing.T) {
// MINIFS // MINIFS
"=MINIFS()": "MINIFS requires at least 3 arguments", "=MINIFS()": "MINIFS requires at least 3 arguments",
"=MINIFS(F2:F4,A2:A4,\"<0\",D2:D9)": "#N/A", "=MINIFS(F2:F4,A2:A4,\"<0\",D2:D9)": "#N/A",
// PEARSON
"=PEARSON()": "PEARSON requires 2 arguments",
"=PEARSON(A1:A2,B1:B1)": "#N/A",
"=PEARSON(A4,A4)": "#DIV/0!",
// PERCENTILE.EXC // PERCENTILE.EXC
"=PERCENTILE.EXC()": "PERCENTILE.EXC requires 2 arguments", "=PERCENTILE.EXC()": "PERCENTILE.EXC requires 2 arguments",
"=PERCENTILE.EXC(A1:A4,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", "=PERCENTILE.EXC(A1:A4,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
@ -3047,6 +3055,10 @@ func TestCalcCellValue(t *testing.T) {
"=RANK.EQ(-1,A1:B5)": "#N/A", "=RANK.EQ(-1,A1:B5)": "#N/A",
"=RANK.EQ(\"\",A1:B5)": "strconv.ParseFloat: parsing \"\": invalid syntax", "=RANK.EQ(\"\",A1:B5)": "strconv.ParseFloat: parsing \"\": invalid syntax",
"=RANK.EQ(1,A1:B5,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", "=RANK.EQ(1,A1:B5,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
// RSQ
"=RSQ()": "RSQ requires 2 arguments",
"=RSQ(A1:A2,B1:B1)": "#N/A",
"=RSQ(A4,A4)": "#DIV/0!",
// SKEW // SKEW
"=SKEW()": "SKEW requires at least 1 argument", "=SKEW()": "SKEW requires at least 1 argument",
"=SKEW(\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", "=SKEW(\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",

Loading…
Cancel
Save