Delphi 如何对一列数字进行排序,同时保留每个数字的原始位置

Delphi 如何对一列数字进行排序,同时保留每个数字的原始位置,delphi,lazarus,Delphi,Lazarus,我想为中位数的Wilcoxon符号秩检验(一种统计非参数检验)编写代码,因为我需要做数百次。我发现自己被困在测试的关键步骤的代码中,希望有人能够帮助我 测试包括以下步骤: 从一列值开始 从每个值中减去一个常数,得到一列差值(保留+/-符号) 现在去掉所有符号,只得到正值(所以绝对差值) 按数量级(1到n)对这些绝对差异进行排序 在步骤2中添加仅与正差异相关联的列组 我陷入了第5步:如何将等级与第2步中的值关联? 以下是我到目前为止的情况: //Subtract HypMed from value

我想为中位数的Wilcoxon符号秩检验(一种统计非参数检验)编写代码,因为我需要做数百次。我发现自己被困在测试的关键步骤的代码中,希望有人能够帮助我

测试包括以下步骤:

  • 从一列值开始

  • 从每个值中减去一个常数,得到一列差值(保留+/-符号)

  • 现在去掉所有符号,只得到正值(所以绝对差值)

  • 按数量级(1到n)对这些绝对差异进行排序

  • 在步骤2中添加仅与正差异相关联的列组

  • 我陷入了第5步:如何将等级与第2步中的值关联?
    以下是我到目前为止的情况:

    //Subtract HypMed from values in Column and put abs diffs in array
    SetLength(AbsDiffVals, CtrlsList.Count)
    for J := 0 to CtrlsList.Count - 1 do 
    begin
      Diff := StrToFloat(CtrlsList[J]) - StrToFloat(HypMed);
      DiffVals.Add(FloatToStr(Diff));
      AbsDiff := Abs(Diff);
      AbsDiffVals[J] := AbsDiff;
    end;
    

    //排序数组AbsDiffVals
    对于J:=0到长度(AbsDiffVals)-2 do
    开始
    对于K:=J+1到长度(AbsDiffVals)-1 do
    开始
    如果AbsDiffVals[J]AbsDiffVals[K],则
    开始
    Temp1:=AbsDiffVals[J];
    Temp2:=AbsDiffVals[K];
    AbsDiffVals[J]:=Temp2;
    AbsDiffVals[K]:=Temp1;
    结束;
    结束;
    结束;
    

    现在我需要将数组中每个值的位置(AbsDiffVals)与TStringList DiffVals中相应的符号相关联,AbsDiffVals是值的秩。这就是我遇到的问题,我需要一些帮助。

    我相信我已经找到了回答我问题的代码,但我确实有几个问题。这是代码。我将在代码之后提出问题

    //Subtract HypMed from values in Column and put abs diffs in array
    SetLength(AbsDiffVals, CtrlsList.Count)
    for J := 0 to CtrlsList.Count - 1 do 
    begin
      Diff := StrToFloat(CtrlsList[J]) - StrToFloat(HypMed);
      DiffVals.Add(FloatToStr(Diff));
      AbsDiff := Abs(Diff);
      AbsDiffVals[J] := AbsDiff;
    end;
    

    //排序数组AbsDiffVals
    对于J:=0到长度(AbsDiffVals)-2 do
    开始
    对于K:=J+1到长度(AbsDiffVals)-1 do
    开始
    如果AbsDiffVals[J]AbsDiffVals[K],则
    开始
    Temp1:=AbsDiffVals[J];
    Temp2:=AbsDiffVals[K];
    AbsDiffVals[J]:=Temp2;
    AbsDiffVals[K]:=Temp1;
    结束;
    结束;
    结束;
    //把绝对的差异放在一个小格子里
    对于J:=0到长度(AbsDiffVals)-1 do
    开始
    Add(FloatToStr(AbsDiffVals[J]);
    结束;
    //将排序后的值与DiffVals中相应值的符号相关联
    //如果登录差异为-,也将-sign分配给rank;else+符号
    设定长度(RankVals,长度(AbsDiffVals));
    对于J:=0到DiffVals.Count-1 do
    开始
    温度:=Abs(StrToFloat(DiffVals[J]);
    排名:=AbsDiffValsList.IndexOf(FloatToStr(Temp))+1//找到值的秩
    如果StrToFloat(DiffVals[J])<0,则秩:=秩*-1
    其他等级:=等级*1;
    RankVals[J]:=秩;
    结束;
    //将所有负秩替换为0,并保留所有正秩
    对于J:=0到长度(RankVals)-1 do
    开始
    如果RankVals[J]<0,则RankVals[J]:=0
    否则继续;
    结束;
    //将修改后的列组(如果为负数,则为0)存储在TSTringList中,以便保存到文件中
    对于J:=0到长度(RankVals)-1 do
    开始
    RankList.Add(IntToStr(RankVals[J]);
    结束;
    
    这段代码似乎做了我需要它做的事情——对于我的示例数据,它表现良好。但是,我想让这个简单的证据,因为我有数百个数据集,其中一些可能没有表现得那么好。数据可能有两种棘手的方式(我的代码没有明确地处理它们):

  • 如果两个值相同怎么办?我的代码没有显式地处理关系。并列值应给出平均等级
  • 如果两个(或更多)值与常数的距离相等,但一个较大,另一个较小,该怎么办?然后,在删除AbsDiff中的标志后,我将无法区分它们

  • 有什么建议吗?

    我想我找到了回答我问题的代码,但我确实有几个问题。这是代码。我将在代码之后提出问题

    //Subtract HypMed from values in Column and put abs diffs in array
    SetLength(AbsDiffVals, CtrlsList.Count)
    for J := 0 to CtrlsList.Count - 1 do 
    begin
      Diff := StrToFloat(CtrlsList[J]) - StrToFloat(HypMed);
      DiffVals.Add(FloatToStr(Diff));
      AbsDiff := Abs(Diff);
      AbsDiffVals[J] := AbsDiff;
    end;
    

    //排序数组AbsDiffVals
    对于J:=0到长度(AbsDiffVals)-2 do
    开始
    对于K:=J+1到长度(AbsDiffVals)-1 do
    开始
    如果AbsDiffVals[J]AbsDiffVals[K],则
    开始
    Temp1:=AbsDiffVals[J];
    Temp2:=AbsDiffVals[K];
    AbsDiffVals[J]:=Temp2;
    AbsDiffVals[K]:=Temp1;
    结束;
    结束;
    结束;
    //把绝对的差异放在一个小格子里
    对于J:=0到长度(AbsDiffVals)-1 do
    开始
    Add(FloatToStr(AbsDiffVals[J]);
    结束;
    //将排序后的值与DiffVals中相应值的符号相关联
    //如果登录差异为-,也将-sign分配给rank;else+符号
    设定长度(RankVals,长度(AbsDiffVals));
    对于J:=0到DiffVals.Count-1 do
    开始
    温度:=Abs(StrToFloat(DiffVals[J]);
    排名:=AbsDiffValsList.IndexOf(FloatToStr(Temp))+1//找到值的秩
    如果StrToFloat(DiffVals[J])<0,则秩:=秩*-1
    其他等级:=等级*1;
    RankVals[J]:=秩;
    结束;
    //将所有负秩替换为0,并保留所有正秩
    对于J:=0到长度(RankVals)-1 do
    开始
    如果RankVals[J]<0,则RankVals[J]:=0
    否则继续;
    结束;
    //将修改后的列组(如果为负数,则为0)存储在TSTringList中,以便保存到文件中
    对于J:=0到长度(RankVals)-1 do
    开始
    RankList.Add(IntToStr(RankVals[J]);
    结束;
    
    这段代码似乎做了我需要它做的事情——对于我的示例数据,它表现良好。然而,我想让它简单明了,因为我有数百个数据集,其中一些可能表现得不太好。数据可能有两种棘手的方式(我的代码没有明确地处理它们):

  • 如果两个值相同怎么办?我的代码没有显式地处理关系。并列值应给出平均等级
  • 如果两个(或更多)值与常数的距离相等,但一个较大,另一个较小,该怎么办?然后,在删除AbsDiff中的标志后,我将无法区分它们
  • 有什么建议吗?

    你试过什么
    //sort array AbsDiffVals
    for J := 0 to Length(AbsDiffVals)-2 do
    begin
      for K := J+1 to Length(AbsDiffVals)-1 do
      begin
        if AbsDiffVals[J] < AbsDiffVals[K] then continue
        else if AbsDiffVals[J] > AbsDiffVals[K] then
        begin
          Temp1 := AbsDiffVals[J];
          Temp2 := AbsDiffVals[K];
          AbsDiffVals[J] := Temp2;
          AbsDiffVals[K] := Temp1;
        end;
      end;
    end;   
    
    //put the absolute diffs in a TStringList
    for J := 0 to Length(AbsDiffVals)-1 do
    begin
      AbsDiffValsList.Add(FloatToStr(AbsDiffVals[J]));
    end;
    
    //associate the sorted values with the sign of corresponding value in DiffVals
    //also assign - sign to rank if sign in DiffVals is -; else + sign
    SetLength(RankVals, Length(AbsDiffVals));
    for J := 0 to DiffVals.Count - 1 do
    begin
      Temp := Abs(StrToFloat(DiffVals[J]));
      Rank := AbsDiffValsList.IndexOf(FloatToStr(Temp))+1;//Find the rank of the value
      if StrToFloat(DiffVals[J]) < 0 then Rank := Rank * -1
      else Rank := Rank * 1;
      RankVals[J] := Rank;
    end;
    
    //replace all negative ranks with 0 and retain all positive ranks
    for J := 0 to Length(RankVals) - 1 do
    begin
      if RankVals[J] < 0 then RankVals[J] := 0
      else continue;
    end;               
    
    //store modified ranks (0 if negative) in TSTringList for easy saving to file
    for J := 0 to Length(RankVals) - 1 do
    begin
      RankList.Add(IntToStr(RankVals[J]));
    end;