forust 0.2.1__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of forust might be problematic. Click here for more details.

Files changed (42) hide show
  1. {forust-0.2.1 → forust-0.2.2}/Cargo.toml +2 -2
  2. {forust-0.2.1 → forust-0.2.2}/PKG-INFO +2 -2
  3. {forust-0.2.1 → forust-0.2.2}/README.md +1 -1
  4. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/Cargo.toml +1 -1
  5. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/README.md +1 -1
  6. forust-0.2.2/local_dependencies/forust-ml/dist/forust-0.2.2-cp311-cp311-macosx_10_7_x86_64.whl +0 -0
  7. forust-0.2.2/local_dependencies/forust-ml/dist/forust-0.2.2.tar.gz +0 -0
  8. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/rs-example.md +1 -1
  9. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/src/data.rs +27 -1
  10. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/src/gradientbooster.rs +59 -3
  11. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/src/tree.rs +18 -11
  12. {forust-0.2.1 → forust-0.2.2}/tests/test_booster.py +2 -2
  13. forust-0.2.1/local_dependencies/forust-ml/dist/forust-0.2.1-cp311-cp311-macosx_10_7_x86_64.whl +0 -0
  14. forust-0.2.1/local_dependencies/forust-ml/dist/forust-0.2.1.tar.gz +0 -0
  15. {forust-0.2.1 → forust-0.2.2}/.gitignore +0 -0
  16. {forust-0.2.1 → forust-0.2.2}/LICENSE +0 -0
  17. {forust-0.2.1 → forust-0.2.2}/forust/__init__.py +0 -0
  18. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/.github/workflows/CI.yml +0 -0
  19. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/.gitignore +0 -0
  20. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/.pre-commit-config.yaml +0 -0
  21. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/LICENSE +0 -0
  22. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/benches/forust_benchmarks.rs +0 -0
  23. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/resources/pdp_plot_age.png +0 -0
  24. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/resources/pdp_plot_age_mono.png +0 -0
  25. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/resources/titanic.csv +0 -0
  26. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/resources/tree-image-crop.png +0 -0
  27. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/scripts/make_resources.py +0 -0
  28. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/scripts/run-python-tests.ps1 +0 -0
  29. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/scripts/run-python-tests.sh +0 -0
  30. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/src/binning.rs +0 -0
  31. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/src/constraints.rs +0 -0
  32. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/src/errors.rs +0 -0
  33. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/src/histogram.rs +0 -0
  34. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/src/lib.rs +0 -0
  35. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/src/node.rs +0 -0
  36. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/src/objective.rs +0 -0
  37. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/src/partial_dependence.rs +0 -0
  38. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/src/splitter.rs +0 -0
  39. {forust-0.2.1 → forust-0.2.2}/local_dependencies/forust-ml/src/utils.rs +0 -0
  40. {forust-0.2.1 → forust-0.2.2}/pyproject.toml +0 -0
  41. {forust-0.2.1 → forust-0.2.2}/scratch.py +0 -0
  42. {forust-0.2.1 → forust-0.2.2}/src/lib.rs +0 -0
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "py-forust"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  edition = "2021"
5
5
 
6
6
  # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -10,6 +10,6 @@ crate-type = ["cdylib"]
10
10
 
11
11
  [dependencies]
12
12
  pyo3 = { version = "0.17", features = ["extension-module"] }
13
- forust-ml = { version="0.2.1", path= "local_dependencies/forust-ml" }
13
+ forust-ml = { version="0.2.2", path= "local_dependencies/forust-ml" }
14
14
  numpy = "0.17.2"
15
15
  ndarray = "0.15.1"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: forust
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -47,7 +47,7 @@ pip install forust
47
47
 
48
48
  To use in a rust project add the following to your Cargo.toml file.
49
49
  ```toml
50
- forust-ml = "0.2.1"
50
+ forust-ml = "0.2.2"
51
51
  ```
52
52
 
53
53
  ## Usage
@@ -26,7 +26,7 @@ pip install forust
26
26
 
27
27
  To use in a rust project add the following to your Cargo.toml file.
28
28
  ```toml
29
- forust-ml = "0.2.1"
29
+ forust-ml = "0.2.2"
30
30
  ```
31
31
 
32
32
  ## Usage
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "forust-ml"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  edition = "2021"
5
5
  authors = ["James Inlow <james.d.inlow@gmail.com>"]
6
6
  homepage = "https://github.com/jinlow/forust"
@@ -26,7 +26,7 @@ pip install forust
26
26
 
27
27
  To use in a rust project add the following to your Cargo.toml file.
28
28
  ```toml
29
- forust-ml = "0.2.1"
29
+ forust-ml = "0.2.2"
30
30
  ```
31
31
 
32
32
  ## Usage
@@ -3,7 +3,7 @@
3
3
  To run this example, add the following code to your `Cargo.toml` file.
4
4
  ```toml
5
5
  [dependencies]
6
- forust-ml = "0.2.1"
6
+ forust-ml = "0.2.2"
7
7
  polars = "0.24"
8
8
  reqwest = { version = "0.11", features = ["blocking"] }
9
9
  ```
@@ -119,6 +119,14 @@ impl<'a, T> Matrix<'a, T> {
119
119
  idx
120
120
  }
121
121
 
122
+ /// Get access to a row of the data, as an iterator.
123
+ pub fn get_row_iter(
124
+ &self,
125
+ row: usize,
126
+ ) -> std::iter::StepBy<std::iter::Skip<std::slice::Iter<T>>> {
127
+ self.data.iter().skip(row).step_by(self.rows)
128
+ }
129
+
122
130
  /// Get a slice of a column in the matrix.
123
131
  ///
124
132
  /// * `col` - The index of the column to select.
@@ -138,6 +146,16 @@ impl<'a, T> Matrix<'a, T> {
138
146
  }
139
147
  }
140
148
 
149
+ impl<'a, T> Matrix<'a, T>
150
+ where
151
+ T: Copy,
152
+ {
153
+ /// Get a row of the data as a vector.
154
+ pub fn get_row(&self, row: usize) -> Vec<T> {
155
+ self.get_row_iter(row).copied().collect()
156
+ }
157
+ }
158
+
141
159
  /// A lightweight row major matrix, this is primarily
142
160
  /// for returning data to the user, it is especially
143
161
  /// suited for appending rows to, such as when building
@@ -227,7 +245,6 @@ impl<T> JaggedMatrix<T> {
227
245
  n_records: 0,
228
246
  }
229
247
  }
230
-
231
248
  /// Get the column of a jagged array.
232
249
  pub fn get_col(&self, col: usize) -> &[T] {
233
250
  assert!(col < self.ends.len());
@@ -285,6 +302,15 @@ mod tests {
285
302
  assert_eq!(m.get_col(1), &vec![5, 6, 7]);
286
303
  }
287
304
 
305
+ #[test]
306
+ fn test_matrix_row() {
307
+ let v = vec![1, 2, 3, 5, 6, 7];
308
+ let m = Matrix::new(&v, 3, 2);
309
+ assert_eq!(m.get_row(2), vec![3, 7]);
310
+ assert_eq!(m.get_row(0), vec![1, 5]);
311
+ assert_eq!(m.get_row(1), vec![2, 6]);
312
+ }
313
+
288
314
  #[test]
289
315
  fn test_jaggedmatrix_get_col() {
290
316
  let vecs = vec![vec![0], vec![5, 4, 3, 2], vec![4, 5]];
@@ -216,6 +216,30 @@ impl GradientBooster {
216
216
  init_preds
217
217
  }
218
218
 
219
+ // pub fn predict(&self, data: &Matrix<f64>, parallel: bool) -> Vec<f64> {
220
+ // // After we disconvered it's faster materializing the row once, and then
221
+ // // Passing that to each tree, let's see if we can do the same with the booster
222
+ // // prediction...
223
+ // // Clean this up..
224
+ // let mut init_preds = vec![self.base_score; data.rows];
225
+ // if parallel {
226
+ // init_preds.par_iter_mut().enumerate().for_each(|(i, p)| {
227
+ // let pred_row = data.get_row(i);
228
+ // for t in &self.trees {
229
+ // *p += t.predict_row_from_row_slice(&pred_row);
230
+ // }
231
+ // });
232
+ // } else {
233
+ // init_preds.iter_mut().enumerate().for_each(|(i, p)| {
234
+ // let pred_row = data.get_row(i);
235
+ // for t in &self.trees {
236
+ // *p += t.predict_row_from_row_slice(&pred_row);
237
+ // }
238
+ // });
239
+ // }
240
+ // init_preds
241
+ // }
242
+
219
243
  /// Generate predictions on data using the gradient booster.
220
244
  ///
221
245
  /// * `data` - Either a pandas DataFrame, or a 2 dimensional numpy array.
@@ -232,9 +256,41 @@ impl GradientBooster {
232
256
  .collect()
233
257
  };
234
258
  let mut contribs = vec![0.; (data.cols + 1) * data.rows];
235
- self.trees.iter().zip(weights.iter()).for_each(|(t, w)| {
236
- t.predict_contributions(data, &mut contribs, w, parallel);
237
- });
259
+
260
+ // Add the bias term to every bias value...
261
+ let bias_idx = data.cols + 1;
262
+ contribs
263
+ .iter_mut()
264
+ .skip(bias_idx - 1)
265
+ .step_by(bias_idx)
266
+ .for_each(|v| *v += self.base_score);
267
+
268
+ // Clean this up..
269
+ // materializing a row, and then passing that to all of the
270
+ // trees seems to be the fastest approach (5X faster), we should test
271
+ // something like this for normal predictions.
272
+ if parallel {
273
+ data.index
274
+ .par_iter()
275
+ .zip(contribs.par_chunks_mut(data.cols + 1))
276
+ .for_each(|(row, c)| {
277
+ let r_ = data.get_row(*row);
278
+ self.trees.iter().zip(weights.iter()).for_each(|(t, w)| {
279
+ t.predict_contributions_row(&r_, c, w);
280
+ });
281
+ });
282
+ } else {
283
+ data.index
284
+ .iter()
285
+ .zip(contribs.chunks_mut(data.cols + 1))
286
+ .for_each(|(row, c)| {
287
+ let r_ = data.get_row(*row);
288
+ self.trees.iter().zip(weights.iter()).for_each(|(t, w)| {
289
+ t.predict_contributions_row(&r_, c, w);
290
+ });
291
+ });
292
+ }
293
+
238
294
  contribs
239
295
  }
240
296
 
@@ -118,15 +118,9 @@ impl Tree {
118
118
  }
119
119
  }
120
120
  }
121
- pub fn predict_contributions_row(
122
- &self,
123
- data: &Matrix<f64>,
124
- row: usize,
125
- contribs: &mut [f64],
126
- weights: &[f64],
127
- ) {
121
+ pub fn predict_contributions_row(&self, row: &[f64], contribs: &mut [f64], weights: &[f64]) {
128
122
  // Add the bias term first...
129
- contribs[data.cols] += weights[0];
123
+ contribs[contribs.len() - 1] += weights[0];
130
124
  let mut node_idx = 0;
131
125
  loop {
132
126
  let node = &self.nodes[node_idx];
@@ -134,7 +128,7 @@ impl Tree {
134
128
  break;
135
129
  }
136
130
  // Get change of weight given child's weight.
137
- let child_idx = node.get_child_idx(data.get(row, node.split_feature));
131
+ let child_idx = node.get_child_idx(&row[node.split_feature]);
138
132
  let node_weight = weights[node_idx];
139
133
  let child_weight = weights[child_idx];
140
134
  let delta = child_weight - node_weight;
@@ -154,9 +148,10 @@ impl Tree {
154
148
  .iter()
155
149
  .zip(contribs.chunks_mut(data.cols + 1))
156
150
  .for_each(|(row, contribs)| {
157
- self.predict_contributions_row(data, *row, contribs, weights)
151
+ self.predict_contributions_row(&data.get_row(*row), contribs, weights)
158
152
  })
159
153
  }
154
+
160
155
  fn predict_contributions_parallel(
161
156
  &self,
162
157
  data: &Matrix<f64>,
@@ -168,7 +163,7 @@ impl Tree {
168
163
  .par_iter()
169
164
  .zip(contribs.par_chunks_mut(data.cols + 1))
170
165
  .for_each(|(row, contribs)| {
171
- self.predict_contributions_row(data, *row, contribs, weights)
166
+ self.predict_contributions_row(&data.get_row(*row), contribs, weights)
172
167
  })
173
168
  }
174
169
 
@@ -198,6 +193,18 @@ impl Tree {
198
193
  }
199
194
  }
200
195
 
196
+ pub fn predict_row_from_row_slice(&self, row: &[f64]) -> f64 {
197
+ let mut node_idx = 0;
198
+ loop {
199
+ let node = &self.nodes[node_idx];
200
+ if node.is_leaf {
201
+ return node.weight_value as f64;
202
+ } else {
203
+ node_idx = node.get_child_idx(&row[node.split_feature]);
204
+ }
205
+ }
206
+ }
207
+
201
208
  fn predict_single_threaded(&self, data: &Matrix<f64>) -> Vec<f64> {
202
209
  data.index
203
210
  .iter()
@@ -278,7 +278,7 @@ def test_booster_to_xgboosts_with_contributions(X_y):
278
278
  objective_type="LogLoss",
279
279
  nbins=500,
280
280
  parallel=False,
281
- base_score=0.0,
281
+ base_score=0.5,
282
282
  )
283
283
  fmod.fit(X, y=y)
284
284
  fmod_preds = fmod.predict(X)
@@ -299,7 +299,7 @@ def test_booster_to_xgboosts_with_contributions(X_y):
299
299
  eval_metric="auc",
300
300
  tree_method="hist",
301
301
  max_bin=10000,
302
- base_score=0.0,
302
+ base_score=0.5,
303
303
  )
304
304
  xmod.fit(X, y)
305
305
  xmod_preds = xmod.predict(X, output_margin=True)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes