@@ -1292,7 +1292,7 @@ cdef class Tree:
1292
1292
cdef intp_t max_n_classes = self .max_n_classes
1293
1293
cdef int k, c, node_idx, sample_idx = 0
1294
1294
cdef int32_t[:, ::1 ] count_oob_values = np.zeros((node_count, n_outputs), dtype = np.int32)
1295
- cdef float64_t * value_at_node = self .value + node_idx * n_outputs * max_n_classes
<
579F
/tr>
1295
+ cdef int node_value_idx = - 1
1296
1296
1297
1297
cdef Node* node
1298
1298
@@ -1304,7 +1304,6 @@ cdef class Tree:
1304
1304
# root node
1305
1305
node = self .nodes
1306
1306
node_idx = 0
1307
- value_at_node = self .value + node_idx * n_outputs * max_n_classes
1308
1307
has_oob_sample[node_idx] = 1
1309
1308
for k in range (n_outputs):
1310
1309
if n_classes[k] > 1 :
@@ -1315,7 +1314,8 @@ cdef class Tree:
1315
1314
count_oob_values[node_idx, k] += 1
1316
1315
else :
1317
1316
if method == " ufi"
B429
span>:
1318
- oob_node_values[node_idx, 0 , k] += (y_test[k, sample_idx] - value_at_node[k]) ** 2.0
1317
+ node_value_idx = node_idx * self .value_stride + k * max_n_classes
1318
+ oob_node_values[node_idx, 0 , k] += (y_test[k, sample_idx] - self .value[node_value_idx]) ** 2.0
1319
1319
else :
1320
1320
oob_node_values[node_idx, 0 , k] += y_test[k, sample_idx]
1321
1321
count_oob_values[node_idx, k] += 1
@@ -1326,7 +1326,6 @@ cdef class Tree:
1326
1326
node_idx = node.left_child
1327
1327
else :
1328
1328
node_idx = node.right_child
1329
- value_at_node = self .value + node_idx * n_outputs * max_n_classes
1330
1329
has_oob_sample[node_idx] = 1
1331
1330
node = & self .nodes[node_idx]
1332
1331
for k in range (n_outputs):
@@ -1338,7 +1337,8 @@ cdef class Tree:
1338
1337
count_oob_values[node_idx, k] += 1
1339
1338
else :
1340
1339
if method == " ufi" :
1341
- oob_node_values[node_idx, 0 , k] += (y_test[k, sample_idx] - value_at_node[k]) ** 2.0
1340
+ node_value_idx = node_idx * self .value_stride + k * max_n_classes
1341
+ oob_node_values[node_idx, 0 , k] += (y_test[k, sample_idx] - self .value[node_value_idx]) ** 2.0
1342
1342
else :
1343
1343
oob_node_values[node_idx, 0 , k] += y_test[k, sample_idx]
1344
1344
count_oob_values[node_idx, k] += 1
@@ -1354,12 +1354,13 @@ cdef class Tree:
1354
1354
for c in range (n_classes[k]):
1355
1355
oob_node_values[node_idx, c, k] /= count_oob_values[node_idx, k]
1356
1356
# if leaf store the predictive proba
1357
- if self .nodes[node_idx].left_child == _TREE_LEAF or self .nodes[node_idx].right_child == _TREE_LEAF:
1357
+ if self .nodes[node_idx].left_child == _TREE_LEAF and self .nodes[node_idx].right_child == _TREE_LEAF:
1358
1358
for sample_idx in range (n_samples):
1359
1359
if y_leafs[sample_idx] == node_idx:
1360
1360
for k in range (n_outputs):
1361
1361
for c in range (n_classes[k]):
1362
- oob_pred[sample_idx, c, k] = oob_node_values[node_idx, c, k]
1362
+ node_value_idx = node_idx * self .value_stride + k * max_n_classes + c
1363
+ oob_pred[sample_idx, c, k] = self .value[node_value_idx]
1363
1364
1364
1365
cpdef compute_unbiased_feature_importance_and_oob_predictions(self , object X_test, object y_test, criterion, method = " ufi" ):
1365
1366
cdef intp_t n_samples = X_test.shape[0 ]
@@ -1377,12 +1378,7 @@ cdef class Tree:
1377
1378
cdef Node* nodes = self .nodes
1378
1379
cdef Node node = nodes[0 ]
1379
1380
cdef int k, c, offset, node_idx = 0
1380
- cdef int left_idx = - 1
1381
- cdef int right_idx = - 1
1382
-
1383
- cdef float64_t* value_at_node = self .value + node_idx * n_outputs * max_n_classes
1384
- cdef float64_t* value_at_left = self .value + left_idx * n_outputs * max_n_classes
1385
- cdef float64_t* value_at_right = self .value + right_idx * n_outputs * max_n_classes
1381
+ cdef int left_idx, right_idx, node_value_idx, left_value_idx, right_value_idx = - 1
1386
1382
1387
1383
cdef intp_t[:, ::1 ] y_view = np.ascontiguousarray(y_test, dtype = np.intp)
1388
1384
self ._compute_oob_node_values_and_predictions(X_test, y_view, oob_pred, has_oob_sample, oob_node_values, method)
@@ -1394,45 +1390,43 @@ cdef class Tree:
1394
1390
left_idx = node.left_child
1395
1391
right_idx = node.right_child
1396
1392
if has_oob_sample[left_idx] and has_oob_sample[right_idx]:
1397
- value_at_node = self .value + node_idx * n_outputs * max_n_classes
1398
- value_at_left = self .value + left_idx * n_outputs * max_n_classes
1399
- value_at_right = self .value + right_idx * n_outputs * max_n_classes
1400
- offset= 0
1401
1393
if method == " ufi" :
1402
1394
for k in range (n_outputs):
1403
1395
if n_classes[k] > 1 : # Classification
1404
1396
for c in range (n_classes[k]):
1397
+ node_value_idx = node_idx * self .value_stride + k * max_n_classes + c
1398
+ left_value_idx = left_idx * self .value_stride + k * max_n_classes + c
1399
+ right_value_idx = right_idx * self .value_stride + k * max_n_classes + c
1405
1400
if criterion == " gini" :
1406
1401
importances[node.feature] -= (
1407
- value_at_node[offset + c ] * oob_node_values[node_idx, c, k]
1402
+ self .value[node_value_idx ] * oob_node_values[node_idx, c, k]
1408
1403
* node.weighted_n_node_samples
1409
1404
-
1410
- value_at_left[offset + c ] * oob_node_values[left_idx, c, k]
1405
+ self .value[left_value_idx ] * oob_node_values[left_idx, c, k]
1411
1406
* nodes[left_idx].weighted_n_node_samples
1412
1407
-
1413
- value_at_right[offset + c ] * oob_node_values[right_idx, c, k]
1408
+ self .value[right_value_idx ] * oob_node_values[right_idx, c, k]
1414
1409
* nodes[right_idx].weighted_n_node_samples
1415
1410
)
1416
1411
elif criterion == " log_loss" :
1417
1412
importances[node.feature] -= (
1418
- (value_at_node[offset + c ] * log(oob_node_values[node_idx, c, k])
1419
- + log(value_at_node[offset + c ]) * oob_node_values[node_idx, c, k])
1413
+ (self .value[node_value_idx ] * log(oob_node_values[node_idx, c, k])
1414
+ + log(self .value[node_value_idx ]) * oob_node_values[node_idx, c, k])
1420
1415
* node.weighted_n_node_samples
1421
1416
)
1422
1417
# If one of the children is pure for oob or inbag samples, set the cross entropy to 0
1423
- if oob_node_values[left_idx, c, k] > 0.0 and value_at_left[offset + c ] > 0.0 :
1418
+ if oob_node_values[left_idx, c, k] > 0.0 and self .value[left_value_idx ] > 0.0 :
1424
1419
importances[node.feature] += (
1425
- (value_at_left[offset + c ] * log(oob_node_values[left_idx, c, k])
1426
- + log(value_at_left[offset + c ]) * oob_node_values[left_idx, c, k])
1420
+ (self .value[left_value_idx ] * log(oob_node_values[left_idx, c, k])
1421
+ + log(self .value[left_value_idx ]) * oob_node_values[left_idx, c, k])
1427
1422
* nodes[left_idx].weighted_n_node_samples
1428
1423
)
1429
- if oob_node_values[right_idx, c, k] > 0.0 and value_at_right[offset + c ] > 0.0 :
1424
+ if oob_node_values[right_idx, c, k] > 0.0 and self .value[right_value_idx ] > 0.0 :
1430
1425
importances[node.feature] += (
1431
- (value_at_right[offset + c ] * log(oob_node_values[right_idx, c, k])
1432
- + log(value_at_right[offset + c ]) * oob_node_values[right_idx, c, k])
1426
+ (self .value[right_value_idx ] * log(oob_node_values[right_idx, c, k])
1427
+ + log(self .value[right_value_idx ]) * oob_node_values[right_idx, c, k])
1433
1428
* nodes[right_idx].weighted_n_node_samples
1434
1429
)
1435
- offset += n_classes[k]
1436
1430
else : # Regression
1437
1431
importances[node.feature] += (
1438
1432
(node.impurity + oob_node_values[node_idx, 0 , k])
@@ -1448,16 +1442,18 @@ cdef class Tree:
1448
1442
elif method == " mdi_oob" :
1449
1443
for k in range (n_outputs):
1450
1444
for c in range (n_classes[k]):
1445
+ node_value_idx = node_idx * self .value_stride + k * max_n_classes + c
1446
+ left_value_idx = left_idx * self .value_stride + k * max_n_classes + c
1447
+ right_value_idx = right_idx * self .value_stride + k * max_n_classes + c
1451
1448
importances[node.feature] += (
1452
- (value_at_node[offset + c ] - value_at_left[offset + c ])
1449
+ (self .value[node_value_idx ] - self .value[left_value_idx ])
1453
1450
* (oob_node_values[node_idx, c , k] - oob_node_values[left_idx, c, k])
1454
1451
* nodes[left_idx].weighted_n_node_samples
1455
1452
+
1456
- (value_at_node[offset + c ] - value_at_right[offset + c ])
1453
+ (self .value[node_value_idx ] - self .value[right_value_idx ])
1457
1454
* (oob_node_values[node_idx, c, k] - oob_node_values[right_idx, c, k])
1458
1455
* nodes[right_idx].weighted_n_node_samples
1459
1456
)
1460
- offset += n_classes[k]
1461
1457
importances[node.feature] /= n_outputs
1462
1458
else :
1463
1459
raise (ValueError (method))
0 commit comments