ningshuxia
2025-04-16 a67da735b33be01b24845ce03ae7551cf55ddbbc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
using MathNet.Numerics.Distributions;
 
namespace IStation.Test
{
    public static class CorrelationHelper
    {
 
        /// <summary>
        /// 计算皮尔逊相关系数及显著性p值
        /// </summary>
        public static (double r, double pValue) PearsonTest(double[] x, double[] y)
        {
            // 计算皮尔逊相关系数
            double r = Pearson(x, y);
 
            // 计算显著性p值(双尾t检验)
            int n = x.Length;
            double t = r * Math.Sqrt((n - 2) / (1 - r * r));
            var tDist = new StudentT(location: 0, scale: 1, freedom: n - 2);
            double pValue = 2 * (1 - tDist.CumulativeDistribution(Math.Abs(t)));
 
            return (r, pValue);
        }
 
        /// <summary>
        /// 计算斯皮尔曼等级相关系数及显著性p值
        /// </summary>
        public static (double rho, double pValue) SpearmanTest(double[] x, double[] y)
        {
            // 计算斯皮尔曼相关系数
            double rho = Spearman(x, y);
 
            // 大样本正态近似法计算p值
            int n = x.Length;
            double z = rho * Math.Sqrt(n - 1);
            var normalDist = new Normal();
            double pValue = 2 * (1 - normalDist.CumulativeDistribution(Math.Abs(z)));
 
            return (rho, pValue);
        }
 
 
        /// <summary>
        /// 计算皮尔逊积差相关系数
        /// </summary>
        /// <param name="dataA">数据样本A</param>
        /// <param name="dataB">数据样本B</param>
        /// <returns>皮尔逊积差相关系数</returns>
        public static double Pearson(IEnumerable<double> dataA, IEnumerable<double> dataB)
        {
            int n = 0;
            double r = 0.0;
            double meanA = 0;
            double meanB = 0;
            double varA = 0;
            double varB = 0;
 
            using (var ieA = dataA.GetEnumerator())
            using (var ieB = dataB.GetEnumerator())
            {
                while (ieA.MoveNext())
                {
                    if (!ieB.MoveNext())
                    {
                        throw new ArgumentOutOfRangeException("dataB", "数据长度不一致");
                    }
 
                    double currentA = ieA.Current;
                    double currentB = ieB.Current;
 
                    double deltaA = currentA - meanA;
                    double scaleDeltaA = deltaA / ++n;
 
                    double deltaB = currentB - meanB;
                    double scaleDeltaB = deltaB / n;
 
                    meanA += scaleDeltaA;
                    meanB += scaleDeltaB;
 
                    varA += scaleDeltaA * deltaA * (n - 1);
                    varB += scaleDeltaB * deltaB * (n - 1);
                    r += (deltaA * deltaB * (n - 1)) / n;
                }
 
                if (ieB.MoveNext())
                {
                    throw new ArgumentOutOfRangeException("dataA", "数据长度不一致");
                }
            }
 
            return r / Math.Sqrt(varA * varB);
        }
 
        /// <summary>
        /// 计算斯皮尔曼等级相关系数
        /// </summary>
        public static double Spearman(IEnumerable<double> dataA, IEnumerable<double> dataB)
        {
            return Pearson(Rank(dataA), Rank(dataB));
        }
 
        private static IEnumerable<double> Rank(IEnumerable<double> sequence)
        {
            var sorted = new List<double>(sequence);
            sorted.Sort();
 
            return (IEnumerable<double>)sequence.Select(x => (double)sorted.IndexOf(x) + 1);
        }
    }
}