【问题标题】:Compute recursion for one column conditionally on values in another columns有条件地根据另一列中的值计算一列的递归
【发布时间】:2018-07-30 03:11:38
【问题描述】:

我获得了名为 Temp.dat 的数据集,其中包含 2 列 (Dataset here)。我最初形成了名为 structure data_t data[100] 的结构,以便我可以根据第一列以递增的顺序排列列 (Column 0 = min(failure time, censored time),第 1 列表示1 = 死亡观察,0 = 截尾观察)。结构化数据集的一部分具有以下形式

0.064295 1 
0.070548 1 
0.070850 1 
0.071508 0 
0.077981 1 
0.086628 1 
0.088239 1 
0.090754 1 
0.093260 0 
0.094090 1 
0.094367 1 
0.097019 1 
0.099336 1 
0.103765 1 
0.103961 1 
0.111674 0 
0.122609 0 
0.123730 1 

现在,我想编写 C 代码以形成不同的时间段,其端点始终以第二列中的条目 1 结尾。如下所示:

预期输出 - 添加了第 3 列(时间间隔)

0.064295 1 [0 0.064295)        
0.070548 1 [0.064295 0.070548) 
0.070850 1 [0.070548 0.070850) 
0.071508 0 [0.070850 0.077891) ---> Skip 0.071508 here because of 0 in column 1 
0.077981 1 [0.070850 0.077981)
0.086628 1 [0.077981 0.086628) 
0.088239 1 [0.086628 0.088239) 
0.090754 1 [0.088239 0.090754) 
0.093260 0 [0.090754 0.094090) 
0.094090 1 [0.090754 0.094090) 
0.094367 1 [0.094090 0.094367) 
0.097019 1 [0.094367 0.097019) 
0.099336 1 [0.097019 0.099336) 
0.103765 1 [0.099336 0.103765) 
0.103961 1 [0.103765 0.103961) 
0.111674 0 [0.103961 0.123730) 
0.122609 0 [0.103961 0.123730) 
0.123730 1 [0.103961 0.123730)

到目前为止,我无法编写代码来执行此操作。因此,如果有人可以在这一步上提供帮助,我将不胜感激。

接下来,我编写了以下代码以获得如下所示的输出。请注意,第 2 列不是我想要的,但这是迄今为止我能得到的最好的

  double array[8][MAX];
  double total = 100;
  for(int i = 0; i < MAX; i++) { 
    double start = 0;
    double count = 0;
    if(i) start = data[i - 1].x; 
    array[0][i] = data[i].x; 
    array[1][i] = data[i].y; 
    array[2][i] = start; 
    array[3][i] = data[i].x;
    array[4][0] = count;
    array[5][0] = count;
    array[6][0] = total;
    array[7][0] = 1;
    /*keep track of number of deaths and censors at each time t_i*/
    if (fmod(arr[1][i], 2.0) == 1)
      {arr[4][i+1]  = count + 1.0;
       arr[5][i+1]  = count;
      }
    else {arr[4][i+1] = count;
          arr[5][i+1] = count + 1.0;
         }

  return(0);
}

样本输出

0.064295 1 [0.060493 0.064295) 1.000000 0.000000 191.000000 0.950000
0.070548 1 [0.064295 0.070548) 1.000000 0.000000 190.000000 0.945000
0.070850 1 [0.070548 0.070850) 1.000000 0.000000 189.000000 0.940000
0.071508 0 [0.070850 0.071508) 1.000000 0.000000 188.000000 0.940000
0.077981 1 [0.071508 0.077981) 0.000000 1.000000 187.000000 0.935000
0.086628 1 [0.077981 0.086628) 1.000000 0.000000 186.000000 0.929973
0.088239 1 [0.086628 0.088239) 1.000000 0.000000 185.000000 0.924946
0.090754 1 [0.088239 0.090754) 1.000000 0.000000 184.000000 0.919919
0.093260 0 [0.090754 0.093260) 1.000000 0.000000 183.000000 0.919919

第 7 列代表生存分布函数的 KM 估计量。它是根据以下规则计算的: 1. 如果第 1 列中的第 i 个条目为 0,只需将第 6 列中对应的第 i 个条目保存为与同一列中的前 (i-1) 个条目相等。 2. 如果第 1 列中的第 i 个条目是 1,但在它之前的一个或多个连续条目是 0(例如,第 1 列的最后一个条目紧跟在两个 0 之前),我们计算相应的 i - 第 6 列中的第 条目,公式为:(i-1)-第条目*(1- 1/(第 5 列中的第 j 个条目)) 其中第 5 列中的第 j 个条目对应于最近第 1 列中的条目 1(例如,第 1 列的最后 4 行中包含 1 0 0 1,这意味着第 6 列中的最后一个条目将计算为 0.890096*(1-1/177) 其中177 =第 5 列中的第一个条目,在第 1 列中有相应的条目 = 1(而不是 0)。

任务要完成:首先,我需要形成 right 列 2,以便 随机输入 t 在第 0 列,代码将在第 6 列给出相应的结果。

其次,我想计算 KM 估计器的方差,使用这个公式:S(t)^2*(summation over t_i

其中 S(t) = 在时间 t 计算的 KM 估计量(上面的第 7 列),d_i 是直到索引 i 的死亡总数(因此,到上面第 5 列的 d_i 条目的总和),r_i =第 6 列中的第 i 个条目。例如,如果 t = 0.071,则 t_i 基于第 0 列只有 3 个可能的值(t_i 将是 0.064295、0.070548 和 0.070850)。我想出了以下工作代码(不确定输出是否正确)

  N = [an integer]; #define size of array here
  double sigma[N];
  sigma[0] = 0;
  double sum[N];
  sum[0] = 0;
  for(int i=1; i< N; i++){
     sum[i] = sum[i-1] + (float)(arr[4][i]/(arr[6][i-1]*(arr[6][i])));
     sigma[i] = pow(arr[7][i],2)*sum[i];
     printf("%.0lf", sigma[i]);
  }

样本输出

0.004775
0.004750
0.004725
0.004700
0.004675
0.004700
0.004650
0.004625
0.004600
0.004575
0.004600
0.004550
0.004525
0.004500
0.004475
0.004450
0.004425
0.004450
0.004450
0.004400
0.004375
0.004350
0.004325
0.004300
0.004275
0.004250
0.004225
0.004200
0.004175
0.004149
0.004124
0.004150
0.004099
0.004074
0.004100
0.004049
0.004024
0.004051
0.003999
0.003974
0.004001
0.003949
0.003976
0.003923
0.003898
0.003926
0.003873
0.003848
0.003823
0.003797
0.003772
0.003747
0.003775
0.003722
0.003750
0.003696
0.003725
0.003671
0.003700
0.003646
0.003676
0.003621
0.003595
0.003570
0.003544
0.003519
0.003549
0.003494

【问题讨论】:

  • 这是一个二维数组。
  • 这里没有很多 C 代码,那为什么要标记为 C?
  • 你应该重做这个问题。显示输入文件的内容、预期输出和 MCVE(我们在另一个问题中做过)其他人应该能够复制/粘贴代码并编译。
  • 代码无法编译。 minimal reproducible example 获得赞成票。您的选择。
  • 我无法对此做出正面和反面。在另一篇文章中,您提到了相当简单的 Kaplan-Meier 公式。但是我不知道任何一列是什么,我不知道为什么必须对数据进行排序,您使用的数学公式不清楚。第六列只是零和一,与第二列相反。为什么一定要递归计算?如果有 MCVE,其他人可能会熟悉这个问题。

标签: c recursion multidimensional-array


【解决方案1】:

这是部分答案。首先,让我们将数组声明为arr[MAX][8],这意味着您有MAX 行和8 列。这样可以更轻松地对数据进行排序。

接下来,让我们创建更易于查看的虚拟数据0.100, 0.101, ...

要查找第 5 列,您可以使用附加循环 (for(int j = i; j &lt; count; j++){...}) 查找下一个非零值。

我们必须跟踪总死数 (dead_count) 并在每次 arr[i][1] 为零时递增。

Kaplan-Meier 公式取为1 - (double)dead_count/(double)count

MCVE 看起来像:

#include <stdlib.h>
#include <stdio.h>

int compare_2d_array(const void *pa, const void *pb)
{
    double a = *(double*)pa;
    double b = *(double*)pb;
    if(a > b) return 1;
    if(a < b) return -1;
    return 0;
}

int main(void)
{
    double arr[][8] =
    {
        { 0.100, 1, 0, 0, 0, 0, 0 , 0 }, //initialize columns
        { 0.101, 1 }, // we can skip adding the zeros, it's done automatically
        { 0.102, 1 },
        { 0.103, 0 },
        { 0.104, 1 },
        { 0.105, 1 },
        { 0.106, 1 },
        { 0.107, 1 },
        { 0.108, 0 },
        { 0.109, 1 },
        { 0.110, 1 },
        { 0.111, 1 },
        { 0.112, 1 },
        { 0.113, 1 },
        { 0.114, 1 },
        { 0.115, 0 },
        { 0.116, 0 },
        { 0.117, 1 },
    };

    int count = sizeof(arr)/sizeof(*arr);

    //sort
    qsort(arr, count, sizeof(arr[0]), compare_2d_array);

    int dead_count = 0;
    for(int i = 0; i < count; i++)
    {
        double start = i ? arr[i - 1][0] : 0;
        double end = arr[i][0]; //<- I don't know what to use as default value!

        //if arr[i][1] is zero, then end should equal the next non-zero value
        double end;
        for(int j = i; j < count; j++)
        {
            end = arr[j][0];
            if(arr[j][1])
                break;
        }

        arr[i][2] = start;
        arr[i][3] = end;
        arr[i][4] = arr[i][1];
        arr[i][5] = !arr[i][1];

        if(!arr[i][1])
            dead_count++;

        printf("%3d %.6lf %.0lf [%.6lf %.6lf) %.0lf %.0lf %3d %.6lf\n", 
            i, 
            arr[i][0], 
            arr[i][1], 
            start,
            end, 
            arr[i][4], 
            arr[i][5], 
            count - i, 1 - (double)dead_count/(double)count );
    }

    return 0;
}

输出:

  0 0.100000 1 [0.000000 0.100000) 1 0  18 1.000000
  1 0.101000 1 [0.100000 0.101000) 1 0  17 1.000000
  2 0.102000 1 [0.101000 0.102000) 1 0  16 1.000000
  3 0.103000 0 [0.102000 0.104000) 0 1  15 0.944444
  4 0.104000 1 [0.103000 0.104000) 1 0  14 0.944444
  5 0.105000 1 [0.104000 0.105000) 1 0  13 0.944444
  6 0.106000 1 [0.105000 0.106000) 1 0  12 0.944444
  7 0.107000 1 [0.106000 0.107000) 1 0  11 0.944444
  8 0.108000 0 [0.107000 0.109000) 0 1  10 0.888889
  9 0.109000 1 [0.108000 0.109000) 1 0   9 0.888889
 10 0.110000 1 [0.109000 0.110000) 1 0   8 0.888889
 11 0.111000 1 [0.110000 0.111000) 1 0   7 0.888889
 12 0.112000 1 [0.111000 0.112000) 1 0   6 0.888889
 13 0.113000 1 [0.112000 0.113000) 1 0   5 0.888889
 14 0.114000 1 [0.113000 0.114000) 1 0   4 0.888889
 15 0.115000 0 [0.114000 0.117000) 0 1   3 0.833333
 16 0.116000 0 [0.115000 0.117000) 0 1   2 0.777778
 17 0.117000 1 [0.116000 0.117000) 1 0   1 0.777778

【讨论】:

  • 感谢@chucks,已修复
  • 非常感谢您的帮助。我尝试使用您的想法修改我上面的代码,现在它可以完美运行了!!现在,我有两个后续问题: 1. 我想将一系列值存储到千离散点(不一定是整数)的数组中,使用输出中的第 7 列(计算不正确)作为 y -值,希望第 2 列作为 x 输入(因此,对于任何给定的 t,如果 t 属于 t 区间 [0.100 0.102),则 y[t] = 1.000000)。我正在考虑做一个嵌套的for循环,但是数组的索引必须是整数,那么我们如何构造这个连续函数y(t)?
  • 对不起,我不知道。这与数学有关,而不是与编程有关。我认为你可以根据1/(dead_count - count)y(t) 进行线性估计——假设每秒有 4 人死亡,那么你会得到popuplation - time * (death/second)! - 您使用的另一个公式是所谓的格林伍德方差公式(维基百科参考),我不明白如何计算方差。
  • 不,我不是想问你一个数学问题。我确信我在上面向您展示的输出是正确的估计量。你在格林伍德的方差公式上也是正确的。我能够找到另一种方法来解决我刚刚在原始评论中提出的问题,但现在我有了另一种方法:我想将 printf() 的所有输出保存到一个文本文件中(用于绘图目的),所以我尝试将freopen ("myoutput.txt","w",stdout) 放在具有printf() 的每一行前面。结果是 myoutput.txt 文件只有 2 个输出,而没有添加 freopen() 则为 1000。
  • 在开始时只调用一次freopen("myoutput.txt","w",stdout)。否则会覆盖旧数据。
猜你喜欢
  • 2019-08-27
  • 1970-01-01
  • 2022-01-23
  • 2012-11-06
  • 2020-11-09
  • 1970-01-01
  • 2021-09-03
  • 2016-07-06
  • 2012-05-29
相关资源
最近更新 更多