方差計算工具類--Java版
阿新 • • 發佈:2018-12-20
方差的計算,如果不太計較精度的話,可以使用 Apache 的 commons-math3(http://commons.apache.org/proper/commons-math/)提供的 Variance 類。不過畢竟 Variance 是使用 double 進行計算,會有精度損失,所以自己寫了個計算方差的工具類,採用 BigDecimal 進行計算,並且可以自己指定精度值,程式碼如下:
package com.frank.test.variance; import java.math.BigDecimal; import com.google.common.base.Preconditions; /** * 方差計算工具類。 * * @author frank */ public final class VarianceUtils { /** * 預設精度 */ private static final int DEFAULT_SCALE = 64; private VarianceUtils() {} public static BigDecimal variance(byte[] arr) { Preconditions.checkNotNull(arr); String[] strArr = new String[arr.length]; for (int i = 0; i < arr.length; i++) { strArr[i] = String.valueOf(arr[i]); } return variance(strArr); } public static BigDecimal variance(byte[] arr, int scale) { Preconditions.checkNotNull(arr); Preconditions.checkArgument(scale > 0, "scale must be positive: " + scale); String[] strArr = new String[arr.length]; for (int i = 0; i < arr.length; i++) { strArr[i] = String.valueOf(arr[i]); } return variance(strArr, scale); } public static BigDecimal variance(char[] arr) { Preconditions.checkNotNull(arr); String[] strArr = new String[arr.length]; for (int i = 0; i < arr.length; i++) { strArr[i] = String.valueOf(arr[i]); } return variance(strArr); } public static BigDecimal variance(char[] arr, int scale) { Preconditions.checkNotNull(arr); Preconditions.checkArgument(scale > 0, "scale must be positive: " + scale); String[] strArr = new String[arr.length]; for (int i = 0; i < arr.length; i++) { strArr[i] = String.valueOf(arr[i]); } return variance(strArr, scale); } public static BigDecimal variance(int[] arr) { Preconditions.checkNotNull(arr); String[] strArr = new String[arr.length]; for (int i = 0; i < arr.length; i++) { strArr[i] = String.valueOf(arr[i]); } return variance(strArr); } public static BigDecimal variance(int[] arr, int scale) { Preconditions.checkNotNull(arr); Preconditions.checkArgument(scale > 0, "scale must be positive: " + scale); String[] strArr = new String[arr.length]; for (int i = 0; i < arr.length; i++) { strArr[i] = String.valueOf(arr[i]); } return variance(strArr, scale); } public static BigDecimal variance(long[] arr) { Preconditions.checkNotNull(arr); String[] strArr = new String[arr.length]; for (int i = 0; i < arr.length; i++) { strArr[i] = String.valueOf(arr[i]); } return variance(strArr); } public static BigDecimal variance(long[] arr, int scale) { Preconditions.checkNotNull(arr); Preconditions.checkArgument(scale > 0, "scale must be positive: " + scale); String[] strArr = new String[arr.length]; for (int i = 0; i < arr.length; i++) { strArr[i] = String.valueOf(arr[i]); } return variance(strArr, scale); } public static BigDecimal variance(float[] arr) { Preconditions.checkNotNull(arr); String[] strArr = new String[arr.length]; for (int i = 0; i < arr.length; i++) { strArr[i] = String.valueOf(arr[i]); } return variance(strArr); } public static BigDecimal variance(float[] arr, int scale) { Preconditions.checkNotNull(arr); Preconditions.checkArgument(scale > 0, "scale must be positive: " + scale); String[] strArr = new String[arr.length]; for (int i = 0; i < arr.length; i++) { strArr[i] = String.valueOf(arr[i]); } return variance(strArr, scale); } public static BigDecimal variance(double[] arr) { Preconditions.checkNotNull(arr); String[] strArr = new String[arr.length]; for (int i = 0; i < arr.length; i++) { strArr[i] = String.valueOf(arr[i]); } return variance(strArr); } public static BigDecimal variance(double[] arr, int scale) { Preconditions.checkNotNull(arr); Preconditions.checkArgument(scale > 0, "scale must be positive: " + scale); String[] strArr = new String[arr.length]; for (int i = 0; i < arr.length; i++) { strArr[i] = String.valueOf(arr[i]); } return variance(strArr, scale); } private static BigDecimal variance(String[] arr) { return variance(arr, DEFAULT_SCALE); } private static BigDecimal variance(String[] arr, int scale) { BigDecimal sum = BigDecimal.ZERO; for (int i = 0; i < arr.length; i++) { sum = sum.add(new BigDecimal(arr[i])); } BigDecimal meanNum = sum.divide(new BigDecimal(arr.length), scale, BigDecimal.ROUND_HALF_DOWN); BigDecimal tmp = null; BigDecimal tmpSum = BigDecimal.ZERO; for (int i = 0; i < arr.length; i++) { tmp = meanNum.subtract(new BigDecimal(arr[i])); tmpSum = tmpSum.add(tmp.multiply(tmp)); } BigDecimal vari = tmpSum.divide(new BigDecimal(arr.length - 1), scale, BigDecimal.ROUND_HALF_DOWN); return new BigDecimal(trimZero(vari.toString())); } /** * 去除小數中後面多餘的0 * * @param str * @return */ private static String trimZero(String str) { if (!str.contains(".")) { return str; } StringBuilder ret = new StringBuilder(); char[] chars = str.toCharArray(); for (int i = chars.length - 1; i >= 0; i--) { char ch = chars[i]; if (ch != '0') { ret.append(ch); } } return ret.reverse().toString(); } }
該工具類是使用最基本的方差計算公式進行計算的,如果要使用流式方式計算方差,可以參考以下文章: