我正在学习C#,我正在尝试实现一个多功能的RandomVar类以及一些计算常见统计数据的方法。我希望能够通过实例化维度N的新变量来从其组件形成任意联合概率RandomVariable,其中N被传递到构造函数中。我想将随机Var X实现为两个一维的双精度列表,而randomVar XY不是两个长度为n ^ 2的列表,而是作为double [] []类型的randomVar,否则仍然可以使用全部相同的方法(ExpectedValue,Covariance等)。
我在执行此操作时遇到了很多麻烦。除了第一个天真的方法(有很多复制和粘贴)之外,我已经尝试从一个基本的RandomVar类继承到一个JointRandomVar类 - 仍然有很多复制粘贴。现在我尝试将类RandomVar的概率和结果数组作为List类型的泛型 - 这会产生很多问题,因为我无法弄清楚如何以适应性的方式编写方法(The std_Dev方法一般不能迭代它所需要的方式 - 所以我需要一些灵活的方法来定义方法,这样如果随机Var的"维度是#2;那么std_Dev方法会做一个双循环,或者为迭代过程弄平数组)。
想要更有经验的程序员提供一些设计帮助 - 是否有概率/结果数组列出传递这样一个参数的最佳方法?
非常感谢你的帮助。
编辑:这是所有双打的代码版本,因此人们可以阅读它,因为未更新的版本似乎让人更加困惑。我希望能够让所有这些方法都适用于任何数组维度的double []类型的对象,并且可以使用_values和具有任何维度的_probs来实例化该类。 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Chapter_3_GUI
{
class RandomVar
{
private double[] _values;
private double[] _probs;
private double _mean;
private double _stddev;
private int _length;
private double _evalue;
public RandomVar(double[] values, double[] probs)
{
_values = values;
_probs = probs;
_mean = meanCalc(_values);
_stddev = stddevCalc(_values, _mean);
_length = _values.Length;
_evalue = expectedVal(_probs, _values, _length);
}
public double[] Values
{
get { return _values; }
set { _values = value; }
}
public double Mean
{
get { return _mean; }
}
public double Stdev
{
get { return _stddev; }
}
public static double meanCalc(double[] var)
{
double mean = var.Sum();
return mean;
}
public static double stddevCalc(double[] var, double mean)
{
double[] varianceArr = new double[var.Length];
for (int i = 0; i <= var.Length; i++)
varianceArr[i] = (var[i] - mean) * (var[i] - mean);
double variance = varianceArr.Sum();
double stddev = Math.Sqrt(variance);
return stddev;
{
}
}
public static double[][] multiplyProbs(RandomVar X, RandomVar Y, double[][] cprobMatrix)
{
double[][] probArr = new double[X._length][Y._length];
for (int i=0; i <= probArr.Length; i++)
{
for (int j =0; j <= probArr.Length; j++)
{
probArr[i][j] = Y._probs[j] * cprobMatrix[i][j];
}
}
return probArr;
}
public static RandomVar multiplyVars(RandomVar X, RandomVar Y, Func<double,double> f)
{
double[][] productArr = new double[X._length][Y._length];
for (int i=0; i<= productArr.Length; i++)
{
for (int j=0; j <= productArr.Length; i=j++)
{
productArr[i][j] = f(X._values[i], Y._values[j]);
}
}
double[][] probArr = multiplyProbs(X, Y, cprobMatrix);
RandomVar product = new RandomVar(productArr, probArr);
return product;
}
public static double expectedVal(double[] _probs, double[] _values, int _length)
{
double[] expectedArr = new double[_length];
for (int i = 0; i <= expectedArr.Length; i++)
{
expectedArr[i] = _probs[i] * _values[i];
}
double evalue = expectedArr.Sum();
return evalue;
}
public static double covarianceCalc(RandomVar X, RandomVar Y, Func<double, double> f)
{
RandomVar VarXY = multiplyVars(X, Y, f);
double correlation = expectedVal(VarXY._probs, VarXY._values, VarXY._length);
double covariance = correlation - (X._mean * Y._mean);
return covariance;
}
}
}
答案 0 :(得分:0)
每个维度的基数是否相同?您对“将其视为一个长大小的数组n ^ k”的评论表明它是。也就是说,n
是每个维度中值/概率对的长度。
我的另一个问题是,在两个不同的数组中传递值和概率背后的原因是什么?如果是我,我会声明包含对的struct
,例如:
struct ValueProbPair
{
public readonly double Value;
public readonly double Probability;
public ValueProbPair(double value, double probability)
{
Value = value;
Probability = probability;
}
}
最后,就您的具体问题而言......嗯,目前还不清楚具体的问题是什么。您似乎有一个关于实现此目的的灵活方式的广泛的问题。
在我看来,这里面临的最大挑战(即具有最不直观明显的解决方案的障碍)是你问题的标题:
将数组的维度作为参数传递
您可以使用Array.CreateInstance(Type, int[])
重载来执行此操作,即创建适当的数组对象。恕我直言,如果(但不要求)你可以将价值/概率对合并为一个struct
,它也会更好。
另一个重要的警告是,您将无法获得编译器优化来访问数组元素的好处。你必须使用例如GetValue()
方法,它很可能会阻止编译器直接访问数组元素(理论上这种优化是可行的,但对我来说似乎不太可能)。
因此,例如,您可以执行以下操作:
Array Combine(ValueProbPair[] newDimension, Array previousDimensions)
{
int[] rankLengths = new int[previousDimensions.Rank + 1];
for (int j = 0; j < previousDimensions.Rank; j++)
{
rankLengths[j] = previousDimensions.GetLength(j);
}
rankLengths[previousDimensions.Rank] = newDimension.Length;
Array result = Array.CreateInstance(typeof(ValueProbPair), rankLengths);
// then fill in your matrix using GetValue and SetValue to
// access individual array elements...
// Finally, return the new multi-dimensional array:
return result;
}
访问元素使用params
数组参数的各种数组方法重载,因此您可以毫不费力地编写可以处理任意维矩阵的代码。 E.g:
IEnumerable<double> GetAllValues(Array source)
{
int[] index = new int[source.Rank];
while (true)
{
yield return (double)source.GetValue(index);
int j = 0;
while (++index[j] == source.GetLength(j))
{
index[j] = 0;
if (++j == index.Length)
{
yield break;
}
}
}
}
最后一点注意:为了处理价值/概率,根据您的情况,您可能会发现使用词典完成所有这些操作更有意义。有不同的复杂情况,但基本构建块为Dictionary<double, object>
,其中值为double
或另一个Dictionary<double, object>
。那么如果你正在寻找例如合并概率,您不必扫描值列表,而是可以直接查找它们作为字典中的键。