Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
536 changes: 536 additions & 0 deletions internal/ubjdecode/decode.go

Large diffs are not rendered by default.

121 changes: 121 additions & 0 deletions internal/xgjson/detect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package xgjson

import (
"bufio"
"encoding/binary"
"bytes"
)

// LooksLikeJSON peeks at the buffered reader and returns true if the content
// appears to be an XGBoost JSON model file. It does not advance the reader.
//
// Heuristic: the first non-whitespace byte must be '{', and the string
// "\"learner\"" (the mandatory top-level key in every XGBoost model) must
// appear within the first 512 peeked bytes.
func LooksLikeJSON(r *bufio.Reader) (bool, error) {
buf, err := r.Peek(512)
if len(buf) == 0 {
return false, err
}

// Find first non-whitespace byte; it must be '{'
firstNonWS := -1
for i, b := range buf {
if b != ' ' && b != '\t' && b != '\r' && b != '\n' {
firstNonWS = i
break
}
}
if firstNonWS < 0 || buf[firstNonWS] != '{' {
return false, nil
}

// Confirm the mandatory top-level key is present in the peeked window.
// Every XGBoost JSON model has "learner" as its first object key.
return bytes.Contains(buf, []byte(`"learner"`)), nil
}

// LooksLikeUBJ peeks at the buffered reader and returns true if the content
// appears to be an XGBoost UBJ (Universal Binary JSON) model file. It does
// not advance the reader.
//
// Heuristic: UBJ objects start with '{' (0x7B), and the first key in an
// XGBoost UBJ model is always "learner". We verify the first byte is '{' and
// then parse the UBJ key-length encoding + key bytes from the peek buffer,
// checking that the first key is exactly "learner".
//
// UBJ key lengths are encoded as: <type-marker> <integer-bytes>, where the
// marker is one of: 'i' (int8), 'U' (uint8), 'I' (int16 BE), 'l' (int32 BE),
// 'L' (int64 BE). XGBoost currently uses 'L', so we handle all widths for
// robustness.
func LooksLikeUBJ(r *bufio.Reader) (bool, error) {
// 32 bytes is more than enough: 1 ('{') + 1 (marker) + 8 (int64) + 7 ("learner") = 17
buf, err := r.Peek(32)
if len(buf) < 2 {
return false, err
}

if buf[0] != '{' {
return false, nil
}

// Parse the key length from buf[1:]
keyLen, headerLen, ok := ubjReadLength(buf[1:])
if !ok {
return false, nil
}

// "learner" is 7 bytes
if keyLen != 7 {
return false, nil
}

start := 1 + headerLen
end := start + 7
if end > len(buf) {
return false, nil
}

return bytes.Equal(buf[start:end], []byte("learner")), nil
}

// ubjReadLength parses a UBJ integer-length from b (starting at b[0] which is
// the type marker). Returns (value, bytesConsumed, ok).
func ubjReadLength(b []byte) (value int, consumed int, ok bool) {
if len(b) < 1 {
return 0, 0, false
}
marker := b[0]
switch marker {
case 'i': // int8 — 1 data byte
if len(b) < 2 {
return 0, 0, false
}
return int(int8(b[1])), 2, true
case 'U': // uint8 — 1 data byte
if len(b) < 2 {
return 0, 0, false
}
return int(b[1]), 2, true
case 'I': // int16 BE — 2 data bytes
if len(b) < 3 {
return 0, 0, false
}
v := int16(binary.BigEndian.Uint16(b[1:3]))
return int(v), 3, true
case 'l': // int32 BE — 4 data bytes
if len(b) < 5 {
return 0, 0, false
}
v := int32(binary.BigEndian.Uint32(b[1:5]))
return int(v), 5, true
case 'L': // int64 BE — 8 data bytes
if len(b) < 9 {
return 0, 0, false
}
v := binary.BigEndian.Uint64(b[1:9])
return int(v), 9, true
default:
return 0, 0, false
}
}
110 changes: 110 additions & 0 deletions internal/xgjson/detect_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package xgjson_test

import (
"bufio"
"bytes"
"os"
"testing"

"github.com/dmitryikh/leaves/internal/xgjson"
)

const testdataDir = "testdata/"

func TestLooksLikeJSON(t *testing.T) {
t.Run("real JSON model", func(t *testing.T) {
r := openBuf(t, testdataDir+"test_binary_logistic.json")
if ok, err := xgjson.LooksLikeJSON(r); err != nil || !ok {
t.Errorf("LooksLikeJSON(json) = (%v, %v), want (true, nil)", ok, err)
}
})

t.Run("UBJ file is not JSON", func(t *testing.T) {
r := openBuf(t, testdataDir+"test_binary_logistic.ubj")
if ok, _ := xgjson.LooksLikeJSON(r); ok {
t.Error("LooksLikeJSON(ubj) = true, want false")
}
})

t.Run("empty reader", func(t *testing.T) {
r := bufio.NewReader(bytes.NewReader(nil))
if ok, _ := xgjson.LooksLikeJSON(r); ok {
t.Error("LooksLikeJSON(empty) = true, want false")
}
})

t.Run("random bytes", func(t *testing.T) {
r := bufio.NewReader(bytes.NewReader([]byte{0x00, 0x01, 0x02, 0x03, 0xFF}))
if ok, _ := xgjson.LooksLikeJSON(r); ok {
t.Error("LooksLikeJSON(random bytes) = true, want false")
}
})

t.Run("reader is not consumed", func(t *testing.T) {
f, err := os.Open(testdataDir + "test_binary_logistic.json")
if err != nil {
t.Fatal(err)
}
defer f.Close()
r := bufio.NewReader(f)
xgjson.LooksLikeJSON(r) //nolint:errcheck
// Peek must not consume: a second call should return the same result.
if ok, _ := xgjson.LooksLikeJSON(r); !ok {
t.Error("second LooksLikeJSON call returned false — reader was consumed")
}
})
}

func TestLooksLikeUBJ(t *testing.T) {
t.Run("real UBJ model", func(t *testing.T) {
r := openBuf(t, testdataDir+"test_binary_logistic.ubj")
if ok, err := xgjson.LooksLikeUBJ(r); err != nil || !ok {
t.Errorf("LooksLikeUBJ(ubj) = (%v, %v), want (true, nil)", ok, err)
}
})

t.Run("JSON file is not UBJ", func(t *testing.T) {
r := openBuf(t, testdataDir+"test_binary_logistic.json")
if ok, _ := xgjson.LooksLikeUBJ(r); ok {
t.Error("LooksLikeUBJ(json) = true, want false")
}
})

t.Run("empty reader", func(t *testing.T) {
r := bufio.NewReader(bytes.NewReader(nil))
if ok, _ := xgjson.LooksLikeUBJ(r); ok {
t.Error("LooksLikeUBJ(empty) = true, want false")
}
})

t.Run("random bytes", func(t *testing.T) {
r := bufio.NewReader(bytes.NewReader([]byte{0x00, 0x01, 0x02, 0x03, 0xFF}))
if ok, _ := xgjson.LooksLikeUBJ(r); ok {
t.Error("LooksLikeUBJ(random bytes) = true, want false")
}
})

t.Run("reader is not consumed", func(t *testing.T) {
f, err := os.Open(testdataDir + "test_binary_logistic.ubj")
if err != nil {
t.Fatal(err)
}
defer f.Close()
r := bufio.NewReader(f)
xgjson.LooksLikeUBJ(r) //nolint:errcheck
// Peek must not consume: a second call should return the same result.
if ok, _ := xgjson.LooksLikeUBJ(r); !ok {
t.Error("second LooksLikeUBJ call returned false — reader was consumed")
}
})
}

func openBuf(t *testing.T, path string) *bufio.Reader {
t.Helper()
f, err := os.Open(path)
if err != nil {
t.Fatalf("open %s: %v", path, err)
}
t.Cleanup(func() { f.Close() })
return bufio.NewReader(f)
}
22 changes: 22 additions & 0 deletions internal/xgjson/testdata/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# XGBoost Test Model Data

This directory contains generated XGBoost model files used by the `xgjson` package tests.

## Files

- `train.py` — Python script that generates the test models
- `test1.json` — XGBoost model in JSON format (XGBoost 2.x/3.x)
- `test1.ubj` — XGBoost model in Universal Binary JSON format (XGBoost 2.x/3.x)
- `test1_expected.json` — Input feature vectors with expected raw scores and probabilities

## Regenerating

Requires [uv](https://docs.astral.sh/uv/).

```sh
cd internal/xgjson/testdata
go generate
```

This trains a small XGBoost binary classifier (10 estimators, max_depth=3) on synthetic data
with 3 features, then writes the three output files above. Commit all three output files.
3 changes: 3 additions & 0 deletions internal/xgjson/testdata/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//go:generate uv run train.py

package testdata
1 change: 1 addition & 0 deletions internal/xgjson/testdata/test_binary_logistic.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"learner":{"attributes":{},"feature_names":[],"feature_types":[],"gradient_booster":{"model":{"cats":{"enc":[],"feature_segments":[],"sorted_idx":[]},"gbtree_model_param":{"num_parallel_tree":"1","num_trees":"10"},"iteration_indptr":[0,1,2,3,4,5,6,7,8,9,10],"tree_info":[0,0,0,0,0,0,0,0,0,0],"trees":[{"base_weights":[3.4848927E-8,-1.5204959E0,1.6623036E0,1.1777768E0,-1.6315176E0,7.10179E-1,1.8392156E0,4.33977E-1,7.083949E-2,-5.601467E-1,-1.6758814E-1,3.6204177E-1,-1.5752013E-1,4.071052E-1,5.7988805E-1],"categories":[],"categories_nodes":[],"categories_segments":[],"categories_sizes":[],"default_left":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"id":0,"left_children":[1,3,5,7,9,11,13,-1,-1,-1,-1,-1,-1,-1,-1],"loss_changes":[5.1048126E2,3.3520996E1,1.4945984E1,8.6061764E-1,2.4676788E1,1.0907537E1,1.0265808E0,0E0,0E0,0E0,0E0,0E0,0E0,0E0,0E0],"parents":[2147483647,0,0,1,1,2,2,3,3,4,4,5,5,6,6],"right_children":[2,4,6,8,10,12,14,-1,-1,-1,-1,-1,-1,-1,-1],"split_conditions":[2.733439E-1,-1.8622892E0,5.279944E-1,1.3041685E0,-2.5623593E-1,1.3718903E0,7.7473426E-1,4.33977E-1,7.083949E-2,-5.601467E-1,-1.6758814E-1,3.6204177E-1,-1.5752013E-1,4.071052E-1,5.7988805E-1],"split_indices":[2,0,2,1,2,1,2,0,0,0,0,0,0,0,0],"split_type":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"sum_hessian":[1.9996877E2,1.0448368E2,9.5485085E1,3.7494144E0,1.0073427E2,1.574754E1,7.973755E1,2.4996095E0,1.2498047E0,8.19872E1,1.8747072E1,1.1248243E1,4.499297E0,1.549758E1,6.423997E1],"tree_param":{"num_deleted":"0","num_feature":"3","num_nodes":"15","size_leaf_vector":"1"}},{"base_weights":[3.3946685E-3,-1.1543779E0,1.2591227E0,9.5409256E-1,-1.2454361E0,5.2215135E-1,1.4025306E0,3.727428E-1,2.3597144E-2,-4.3348977E-1,-1.21060215E-1,4.5374906E-1,2.7029645E-2,3.0377525E-1,4.4462258E-1],"categories":[],"categories_nodes":[],"categories_segments":[],"categories_sizes":[],"default_left":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"id":1,"left_children":[1,3,5,7,9,11,13,-1,-1,-1,-1,-1,-1,-1,-1],"loss_changes":[2.7547772E2,2.011644E1,8.874084E0,1.0756211E0,1.5365356E1,6.8806324E0,8.410034E-1,0E0,0E0,0E0,0E0,0E0,0E0,0E0,0E0],"parents":[2147483647,0,0,1,1,2,2,3,3,4,4,5,5,6,6],"right_children":[2,4,6,8,10,12,14,-1,-1,-1,-1,-1,-1,-1,-1],"split_conditions":[2.733439E-1,-1.8622892E0,5.279944E-1,-7.9844646E-2,-2.5623593E-1,-1.8622892E0,7.7473426E-1,3.727428E-1,2.3597144E-2,-4.3348977E-1,-1.21060215E-1,4.5374906E-1,2.7029645E-2,3.0377525E-1,4.4462258E-1],"split_indices":[2,0,2,2,2,0,2,0,0,0,0,0,0,0,0],"split_type":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"sum_hessian":[1.874821E2,9.758766E1,8.989444E1,3.647652E0,9.394001E1,1.5399192E1,7.449525E1,2.428422E0,1.2192299E0,7.53628E1,1.8577206E1,3.9179015E0,1.1481291E1,1.4947725E1,5.954752E1],"tree_param":{"num_deleted":"0","num_feature":"3","num_nodes":"15","size_leaf_vector":"1"}},{"base_weights":[7.773815E-3,-9.943017E-1,9.9700433E-1,2.7761754E-1,-1.076667E0,5.286407E-1,3.7626263E-1,-3.394221E-1,3.191901E-1,2.0238668E-1,-3.8180283E-1],"categories":[],"categories_nodes":[],"categories_segments":[],"categories_sizes":[],"default_left":[0,0,0,0,0,0,0,0,0,0,0],"id":2,"left_children":[1,3,5,-1,7,9,-1,-1,-1,-1,-1],"loss_changes":[1.6563177E2,1.4121422E1,9.465561E0,0E0,1.0584633E1,9.1505995E0,0E0,0E0,0E0,0E0,0E0],"parents":[2147483647,0,0,1,1,2,2,4,4,5,5],"right_children":[2,4,6,-1,8,10,-1,-1,-1,-1,-1],"split_conditions":[2.0596176E-1,-1.8622892E0,7.2267E-1,2.7761754E-1,-4.3772988E-2,2.3320758E0,3.7626263E-1,-3.394221E-1,3.191901E-1,2.0238668E-1,-3.8180283E-1],"split_indices":[2,0,2,0,0,1,0,0,0,0,0],"split_type":[0,0,0,0,0,0,0,0,0,0,0],"sum_hessian":[1.6508813E2,8.200907E1,8.307906E1,2.9528005E0,7.905627E1,3.0533514E1,5.254555E1,7.754477E1,1.5115029E0,2.8823126E1,1.7103883E0],"tree_param":{"num_deleted":"0","num_feature":"3","num_nodes":"11","size_leaf_vector":"1"}},{"base_weights":[9.2651285E-3,-1.0554368E0,6.792614E-1,2.3023954E-1,-1.1098394E0,1.0147718E-1,1.0298864E0,-5.1912617E-2,-3.520825E-1,1.7861223E-1,-3.123424E-1,1.9472034E-1,3.3861062E-1],"categories":[],"categories_nodes":[],"categories_segments":[],"categories_sizes":[],"default_left":[0,0,0,0,0,0,0,0,0,0,0,0,0],"id":3,"left_children":[1,3,5,-1,7,9,11,-1,-1,-1,-1,-1,-1],"loss_changes":[1.0307969E2,6.3869324E0,1.786119E1,0E0,3.0589828E0,2.0146532E1,1.3401375E0,0E0,0E0,0E0,0E0,0E0,0E0],"parents":[2147483647,0,0,1,1,2,2,4,4,5,5,6,6],"right_children":[2,4,6,-1,8,10,12,-1,-1,-1,-1,-1,-1],"split_conditions":[-2.5623593E-1,-2.0155988E0,5.279944E-1,2.3023954E-1,-2.6036727E-1,1.3718903E0,7.7473426E-1,-5.1912617E-2,-3.520825E-1,1.7861223E-1,-3.123424E-1,1.9472034E-1,3.3861062E-1],"split_indices":[2,0,2,0,1,1,2,0,0,0,0,0,0],"split_type":[0,0,0,0,0,0,0,0,0,0,0,0,0],"sum_hessian":[1.4249661E2,5.4814583E1,8.768203E1,1.2086432E0,5.3605938E1,3.360115E1,5.4080883E1,3.6531324E0,4.9952805E1,2.379479E1,9.806361E0,1.2701178E1,4.1379704E1],"tree_param":{"num_deleted":"0","num_feature":"3","num_nodes":"13","size_leaf_vector":"1"}},{"base_weights":[6.5199593E-3,-9.5052385E-1,5.596426E-1,2.0603801E-1,-1.0059912E0,7.9649486E-2,9.219858E-1,-3.384241E-1,-1.2668663E-1,1.2908778E-1,-2.4213417E-1,1.5698004E-1,3.0862683E-1],"categories":[],"categories_nodes":[],"categories_segments":[],"categories_sizes":[],"default_left":[0,0,0,0,0,0,0,0,0,0,0,0,0],"id":4,"left_children":[1,3,5,-1,7,9,11,-1,-1,-1,-1,-1,-1],"loss_changes":[6.568722E1,4.8187065E0,1.3602236E1,0E0,2.6854439E0,1.1204861E1,1.3651428E0,0E0,0E0,0E0,0E0,0E0,0E0],"parents":[2147483647,0,0,1,1,2,2,4,4,5,5,6,6],"right_children":[2,4,6,-1,8,10,12,-1,-1,-1,-1,-1,-1],"split_conditions":[-2.5623593E-1,-2.0155988E0,5.594684E-1,2.0603801E-1,-5.7463634E-1,1.3718903E0,7.7473426E-1,-3.384241E-1,-1.2668663E-1,1.2908778E-1,-2.4213417E-1,1.5698004E-1,3.0862683E-1],"split_indices":[2,0,2,0,2,1,2,0,0,0,0,0,0],"split_type":[0,0,0,0,0,0,0,0,0,0,0,0,0],"sum_hessian":[1.2208248E2,4.445151E1,7.763097E1,1.0835884E0,4.3367924E1,3.391881E1,4.371216E1,3.5094765E1,8.273158E0,2.4676153E1,9.242659E0,1.0479339E1,3.323282E1],"tree_param":{"num_deleted":"0","num_feature":"3","num_nodes":"13","size_leaf_vector":"1"}},{"base_weights":[3.5492254E-3,-5.9674454E-1,6.862838E-1,-1.0244098E0,-1.5051265E-1,3.5410693E-1,9.457186E-1,-1.983951E-2,-3.1750667E-1,-1.2765785E-1,4.3486968E-1,3.8029623E-1,1.0213314E-2,2.9135826E-1,1.1577517E-1],"categories":[],"categories_nodes":[],"categories_segments":[],"categories_sizes":[],"default_left":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"id":5,"left_children":[1,3,5,7,9,11,13,-1,-1,-1,-1,-1,-1,-1,-1],"loss_changes":[4.385949E1,1.0713873E1,3.979826E0,8.703499E-1,1.3396497E1,6.8439E0,1.7572403E-2,0E0,0E0,0E0,0E0,0E0,0E0,0E0,0E0],"parents":[2147483647,0,0,1,1,2,2,3,3,4,4,5,5,6,6],"right_children":[2,4,6,8,10,12,14,-1,-1,-1,-1,-1,-1,-1,-1],"split_conditions":[3.263706E-1,-5.7463634E-1,7.7473426E-1,-1.534747E0,-7.9241884E-1,-1.8355771E0,1.0084084E0,-1.983951E-2,-3.1750667E-1,-1.2765785E-1,4.3486968E-1,3.8029623E-1,1.0213314E-2,2.9135826E-1,1.1577517E-1],"split_indices":[2,2,2,0,0,0,0,0,0,0,0,0,0,0,0],"split_type":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"sum_hessian":[1.0501652E2,5.5949192E1,4.9067326E1,2.7907331E1,2.804186E1,2.255417E1,2.6513155E1,1.0556241E0,2.6851707E1,2.455545E1,3.4864097E0,5.08358E0,1.747059E1,2.4656202E1,1.8569524E0],"tree_param":{"num_deleted":"0","num_feature":"3","num_nodes":"15","size_leaf_vector":"1"}},{"base_weights":[9.643211E-3,-9.6156096E-1,3.2266313E-1,-1.6817693E-2,-1.0025502E0,1.896752E-2,3.062792E-1,-3.163531E-2,-3.1356356E-1,3.1077072E-1,-8.825563E-2],"categories":[],"categories_nodes":[],"categories_segments":[],"categories_sizes":[],"default_left":[0,0,0,0,0,0,0,0,0,0,0],"id":6,"left_children":[1,3,5,-1,7,9,-1,-1,-1,-1,-1],"loss_changes":[2.8589937E1,7.9467964E-1,1.5057805E1,0E0,7.268925E-1,1.6408224E1,0E0,0E0,0E0,0E0,0E0],"parents":[2147483647,0,0,1,1,2,2,4,4,5,5],"right_children":[2,4,6,-1,8,10,-1,-1,-1,-1,-1],"split_conditions":[-5.7463634E-1,-1.534747E0,-7.9241884E-1,-1.6817693E-2,-2.3389478E0,-1.8355771E0,3.062792E-1,-3.163531E-2,-3.1356356E-1,3.1077072E-1,-8.825563E-2],"split_indices":[2,0,0,0,2,0,0,0,0,0,0],"split_type":[0,0,0,0,0,0,0,0,0,0,0],"sum_hessian":[9.202333E1,2.1924986E1,7.009835E1,1.052031E0,2.0872955E1,4.9567326E1,2.0531021E1,1.1051567E0,1.97678E1,1.1126637E1,3.844069E1],"tree_param":{"num_deleted":"0","num_feature":"3","num_nodes":"11","size_leaf_vector":"1"}},{"base_weights":[1.0875948E-2,-9.042081E-1,2.6562464E-1,-1.4255263E-2,-9.5357305E-1,2.432597E-2,9.072643E-1,-2.707678E-2,-3.0165362E-1,1.6966063E-1,-1.2472395E-1,2.841285E-1,9.571609E-2],"categories":[],"categories_nodes":[],"categories_segments":[],"categories_sizes":[],"default_left":[0,0,0,0,0,0,0,0,0,0,0,0,0],"id":7,"left_children":[1,3,5,-1,7,9,11,-1,-1,-1,-1,-1,-1],"loss_changes":[1.9578981E1,7.282772E-1,1.0144684E1,0E0,6.824322E-1,1.1845299E1,1.1762619E-1,0E0,0E0,0E0,0E0,0E0,0E0],"parents":[2147483647,0,0,1,1,2,2,4,4,5,5,6,6],"right_children":[2,4,6,-1,8,10,12,-1,-1,-1,-1,-1,-1],"split_conditions":[-5.7463634E-1,-1.534747E0,-7.9241884E-1,-1.4255263E-2,-2.3389478E0,-1.451989E0,1.0084084E0,-2.707678E-2,-3.0165362E-1,1.6966063E-1,-1.2472395E-1,2.841285E-1,9.571609E-2],"split_indices":[2,0,0,0,2,0,0,0,0,0,0,0,0],"split_type":[0,0,0,0,0,0,0,0,0,0,0,0,0],"sum_hessian":[8.195767E1,1.7292343E1,6.466533E1,1.0490721E0,1.6243273E1,4.7747166E1,1.6918161E1,1.0771346E0,1.5166138E1,2.1285168E1,2.6462E1,1.5273769E1,1.6443915E0],"tree_param":{"num_deleted":"0","num_feature":"3","num_nodes":"13","size_leaf_vector":"1"}},{"base_weights":[8.420152E-3,-8.866207E-1,2.0744449E-1,-2.3173474E-2,-2.8409058E-1,3.5733518E-1,-6.553415E-1,3.0889487E-1,2.7870974E-2,2.424394E-1,-3.562318E-1],"categories":[],"categories_nodes":[],"categories_segments":[],"categories_sizes":[],"default_left":[0,0,0,0,0,0,0,0,0,0,0],"id":8,"left_children":[1,3,5,-1,-1,7,9,-1,-1,-1,-1],"loss_changes":[1.3613471E1,6.0597706E-1,8.315063E0,0E0,0E0,9.483938E0,8.436519E0,0E0,0E0,0E0,0E0],"parents":[2147483647,0,0,1,1,2,2,5,5,6,6],"right_children":[2,4,6,-1,-1,8,10,-1,-1,-1,-1],"split_conditions":[-6.423459E-1,-2.3389478E0,1.8273275E0,-2.3173474E-2,-2.8409058E-1,-1.4220484E0,-2.035454E0,3.0889487E-1,2.7870974E-2,2.424394E-1,-3.562318E-1],"split_indices":[2,2,1,0,0,0,0,0,0,0,0],"split_type":[0,0,0,0,0,0,0,0,0,0,0],"sum_hessian":[7.438975E1,1.2903961E1,6.148579E1,1.053575E0,1.1850386E1,5.2884132E1,8.601657E0,1.4111651E1,3.8772484E1,2.1552174E0,6.4464393E0],"tree_param":{"num_deleted":"0","num_feature":"3","num_nodes":"11","size_leaf_vector":"1"}},{"base_weights":[3.1257947E-3,-2.370009E-1,7.368995E-1,-4.209105E-5,-8.483909E-1,8.1515753E-1,1.465431E-1,3.7057182E-1,-1.14696495E-1,2.5674397E-1,-3.5496542E-1,7.9826936E-2,2.756763E-1,-1.3072331E-1,1.8127826E-1],"categories":[],"categories_nodes":[],"categories_segments":[],"categories_sizes":[],"default_left":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"id":9,"left_children":[1,3,5,7,9,11,13,-1,-1,-1,-1,-1,-1,-1,-1],"loss_changes":[1.2430462E1,7.701972E0,6.841221E-1,1.9037214E1,9.485901E0,6.1796856E-1,1.1308331E0,0E0,0E0,0E0,0E0,0E0,0E0,0E0,0E0],"parents":[2147483647,0,0,1,1,2,2,3,3,4,4,5,5,6,6],"right_children":[2,4,6,8,10,12,14,-1,-1,-1,-1,-1,-1,-1,-1],"split_conditions":[7.2267E-1,1.398677E0,1.8586534E0,-1.2937937E0,-2.0780978E0,6.0014886E-1,1.2276509E0,3.7057182E-1,-1.14696495E-1,2.5674397E-1,-3.5496542E-1,7.9826936E-2,2.756763E-1,-1.3072331E-1,1.8127826E-1],"split_indices":[2,1,1,0,0,1,2,0,0,0,0,0,0,0,0],"split_type":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"sum_hessian":[6.855681E1,5.2163403E1,1.6393408E1,3.8313972E1,1.3849428E1,1.4138422E1,2.254987E0,8.527461E0,2.9786512E1,2.0186934E0,1.1830735E1,2.8137515E0,1.132467E1,1.0135728E0,1.2414142E0],"tree_param":{"num_deleted":"0","num_feature":"3","num_nodes":"15","size_leaf_vector":"1"}}]},"name":"gbtree"},"learner_model_param":{"base_score":"[4.9375E-1]","boost_from_average":"1","num_class":"0","num_feature":"3","num_target":"1"},"objective":{"name":"binary:logistic","reg_loss_param":{"scale_pos_weight":"1"}}},"version":[3,2,0]}
Loading