我正在尝试编码二进制决策树。下面的代码是一个工作的例子,数据分割作为整个算法的一部分,尽管它有一些错误检测的Valgrind。
您可能已经知道,树是由节点组成的。在每个节点中,它通过拆分条件携带所有符合条件的观测值(行)。继续,分割也依赖于这些行。
通过对所有变量和值的贪心搜索可以找到最佳的分割条件,这意味着这个数据分割步骤可以执行数百次来找到最优的分割(通过分类问题中的基尼指数来评估)。我以为用memcpy
会很贵。最糟糕的是,每次尝试分割后,我都必须为复制的行释放内存。
所以,我在想是否有一种方法可以避免使用memcpy
从字面上复制整个数据集,而只是在每次拆分中引用原始数据集的合格行。这样就不需要过量的memcpy
和free
。
问题:对于下面的例子,如何使用一个指针来记录合格行的地址,这样就不需要memcpy
,并且在执行贪婪搜索以获得最佳分割时允许(容易或方便)访问合格行。
欢迎任何帮助和建议。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printArray(double array[], unsigned int size) {
for (unsigned int i = 0; i < size; ++i) {
printf("%.3f ", array[i]);
}
printf("n");
}
double **alloc_2dArray(unsigned int row, unsigned int col)
{
double **Array = (double **) malloc(row * sizeof(double *));
for (unsigned int i = 0; i < row; i++) {
Array[i] = (double *) malloc(col * sizeof(double));
}
return Array;
}
void dealloc_2dArray(double **Array, unsigned int row, unsigned int col)
{
for (unsigned int i = 0; i < row; i++)
{
free(Array[i]);
}
free(Array);
}
int main(){
double **data = alloc_2dArray(4,4);
double delta[4] = {1,0,1,0};
double **dataL = alloc_2dArray(4,4);
double **dataR = alloc_2dArray(4,4);
int i,j;
int k=0;
//data initialization
for(i=0; i<4; i++){
for(j=0; j<4; j++){
data[i][j] = k++;
}
}
int l=0, r=0;
for(i=0; i<4; i++){
if((int)delta[i] ==0){
memcpy(dataL[l++], data[i], 4*sizeof(double));
}else{
memcpy(dataR[r++], data[i], 4*sizeof(double));
}
}
for(i = l; i<4; i++){
free(dataL[i]);
}
printf("l and r are %d %dn", l, r);
dataL = realloc(dataL, l*sizeof(double*));
for(i = r; i<4; i++){
free(dataR[i]);
}
dataR = realloc(dataR, r*sizeof(double*));
for(i=0; i<4; i++){
if(dataL[i] != NULL){
printArray(dataL[i],4);
}
if(dataR[i] != NULL){
printArray(dataR[i],4);
}
}
dealloc_2dArray(data, 4,4);
dealloc_2dArray(dataL, l, 4);
dealloc_2dArray(dataR, r, 4);
return 0;
}
我认为您正在询问是否可以在拆分矩阵中保留原始数据行指针。答案是肯定的,你可以。然而,所有权起了作用。
对于下面的例子(没有memcpy
操作),dataL
和dataR
指针床都是直接分配的,没有实际的数据行分配给它们。这些行是"借用"的。从原始数据矩阵
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printArray(double const array[], unsigned int size)
{
for (unsigned int i = 0; i < size; ++i)
{
printf("%-7.3f", array[i]);
}
printf("n");
}
double **alloc_2dArray(unsigned int row, unsigned int col)
{
double **Array = malloc(row * sizeof(double *));
for (unsigned int i = 0; i < row; i++)
{
Array[i] = (double *)malloc(col * sizeof(double));
}
return Array;
}
void dealloc_2dArray(double **Array, unsigned int row)
{
for (unsigned int i = 0; i < row; i++)
{
free(Array[i]);
}
free(Array);
}
int main()
{
double **data = alloc_2dArray(4,4);
double delta[4] = {1, 0, 1, 0};
double **dataL = calloc(4, sizeof *dataL);
double **dataR = calloc(4, sizeof *dataR);
unsigned int i, j;
double k = 0;
// data initialization
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
data[i][j] = k;
k += 1;
}
}
printf("data[]n");
for (i=0; i<4; ++i)
printArray(data[i], 4);
fputc('n', stdout);
unsigned int l = 0, r = 0;
for (i = 0; i < 4; i++)
{
if ((int)delta[i] == 0)
{
dataL[l++] = data[i];
}
else
{
dataR[r++] = data[i];
}
}
printf("l=%u r=%un", l, r);
dataL = realloc(dataL, l * sizeof(double *));
dataR = realloc(dataR, r * sizeof(double *));
printf("dataL[]n");
for (i=0; i<l; ++i)
printArray(dataL[i], 4);
fputc('n', stdout);
printf("dataR[]n");
for (i=0; i<r; ++i)
printArray(dataR[i], 4);
fputc('n', stdout);
free(dataL);
free(dataR);
dealloc_2dArray(data,4);
return 0;
}
data[]
0.000 1.000 2.000 3.000
4.000 5.000 6.000 7.000
8.000 9.000 10.000 11.000
12.000 13.000 14.000 15.000
l=2 r=2
dataL[]
4.000 5.000 6.000 7.000
12.000 13.000 14.000 15.000
dataR[]
0.000 1.000 2.000 3.000
8.000 9.000 10.000 11.000
关于这些行指针的实际所有权。只有你知道在那里什么是合适的。如果原data
矩阵要继续拥有它们,则必须注意确保在dataL
和dataR
仍在使用时,data
及其行不会被破坏。同样,如果dataR
和dataL
要占用所有权,那么在释放data
时不应该释放这些行(但仍然释放data
的基指针床),并且让dataL
和dataR
的free'ing不仅负责释放它们的基指针床,还负责释放行。
不管怎样,就这样吧。