C# .net 抽稀算法 等距取样

数据抽稀:

  一堆数据,要求尽可能均匀的从中取出数据。例如,从长度为100的数据中取出9个,索引分别是0, 11, 22, 33, 44, 56, 67, 78, 89。

/// <summary>
/// 测试抽稀算法
/// </summary>
/// <param name="inputLen">待抽样数据长度,自动生成</param>
/// <param name="samplLen">抽稀长度</param>        
public List<int>  DataSamplingTest(int inputLen, int samplLen)
{
    //生成待抽稀数据
    List<int> inputData = new List<int>();
    for (int i = 0; i < inputLen; )
    {                
        inputData.Add(i++);//模拟索引值
    }            
    //确定取样数据
    var IndexList= DataSampling(inputLen, samplLen);
    //取样数据
    List<int> retData = new List<int>();
    for (int k = 0; k < IndexList.Count; k++)
    {
        var currentIndex = IndexList[k];
        var currentData = inputData[currentIndex];
        retData.Add(currentData);
    }
    return retData;
}

/// <summary>
///  数据抽样-抽稀算法:等距(尽量)取样取前点,返回的是各取样点在原数据中的索引值的List
/// </summary>
/// <param name="inputLen">待处理数据引长度</param>
/// <param name="samplLen">期望数据长度</param>
/// <returns></returns>
private List<int> DataSampling(int inputLen, int samplLen)
{
    //生成索引列表
    List<int> inputData = new List<int>();
    for (int i = 0; i < inputLen;)
    {
        inputData.Add(i++);
    }
    //取样
    List<int> retData = new List<int>();            
    // inputLen>= len 
    double initStepSize = (double)inputLen / samplLen;//初始步长
    // 兼容inputLen< len 的情况
    if (initStepSize < 1)
        initStepSize = 1;
    List<int> IndexList = new List<int>();//取值索引
    for (int i = 0, n = 0; i < inputLen || n < samplLen; n++)//i是待处理数据的索引,n是循环次数
    {
        var currentInitIndex = n* initStepSize;
        var currentIndex = this.NearestInteger(currentInitIndex);
        if (currentIndex >= inputLen)
        {
            break;
        }
        if (IndexList.Contains(currentIndex))
        {
            currentIndex++;
            if (currentIndex >= inputLen)
                break;
        }
        IndexList.Add(currentIndex);
        i = currentIndex;
    }
    return IndexList;
}       


/// <summary>
/// 取浮点数最接近的整数(优先向下取整)
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private int NearestInteger(double input)
{
    int ret = 0;
    double inputCeiling = Math.Ceiling(input);//向上取整
    double stepSizeFloor = Math.Floor(input);//向下取整
    if (Math.Abs(inputCeiling - input) >= Math.Abs(input - stepSizeFloor))
    {
        ret = (int)stepSizeFloor;
    }
    else 
    {
        ret = (int)inputCeiling;
    }
    return ret;
}

 

此处给出了一种解决方案,即 尽可能的等分数据后,取每一段数据的第一个。

还可以采用 取每段的最后一个数据的方式,或取中间位置数据的方式。

取最后一个数据,大致可修改如下:

List<int> IndexList = new List<int>();//取值索引
    for (int i = 0, n = 1; i < inputLen || n <= samplLen; n++)//i是待处理数据的索引,n是循环次数 -----将n改为从1开始取值,此时可能会出现实际采样数据少于要求的取样次数的情况,做一下判断处理即可
    {
        var currentInitIndex = n* initStepSize;
        var currentIndex = this.NearestInteger(currentInitIndex);
        if (currentIndex >= inputLen)
        {
            break;
        }
        if (IndexList.Contains(currentIndex))
        {
            currentIndex++;
            if (currentIndex >= inputLen)
                break;
        }
        IndexList.Add(currentIndex);
        i = currentIndex;
    }

 

取中间位置数据雷同稍复杂一步,在于确定中间位置是谁,其核心思想与NearestInteger方法类似,此处不再赘述。

 

posted @ 2021-03-24 16:08  深海地平线  阅读(979)  评论(0)    收藏  举报