Modified to speed up UpliftTreeClassifier.growDecisionTreeFrom. #695
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Mainly reduce allocation, in a synthetic data of 40000 rows, about 400 features, 4 treatments, there is a speed up of about 65x over the original version.
The main modifications are in the comments, reproduced below for convenience.
Proposed changes
Modified to speed up UpliftTreeClassifier.growDecisionTreeFrom and
consequently can also speed up UpliftTreeClassifier.fit, and
UpliftRandomForestClassifier.
Modification version 1, on 2023-10-04 by Peter Lo peterloleungyau@gmail.com
created divideSet_len from divideSet, which does not split the whole
X into X_l and X_r, but returns len(X_l) and len(X_r) instead,
because in finding the best split, the whole X_l and X_r are not
used. This saves some allocations.
in finding the best split, we use mostly scalar values
(e.g. best_col and best_value in favor of one single tuple
bestAttribute) to keep the current best, and further avoids
allocating many objects. After finding the best split, we use the
original divideSet to get the X_l and X_r and subsequently
best_set_left and best_set_right which are used in subsequent
construction of subtrees of the left and right branches; and
calculate bestAttribute as a tuple.
also, from the annotation of Cython, it seems some constant values
such as the list of percentile values to test for threshold will be
constructed in each iteration of the loop, because the Cython
compiler cannot be sure that the list will not be modified by
np.percentile, but since we can be sure, we create the list once
outside the loop.
Modification verison 2, on 2023-10-05 by Peter Lo peterloleungyau@gmail.com
modified group_uniqueCounts to group_uniqueCounts_to_arr, to use
pre-allocated flat numpy array to fill in the counts, instead of
using list of list.
modified tree_node_summary to tree_node_summary_to_arr to use
pre-allocated flat numpy arrays, and to fill in the node summary in
new format, which consist of two parallel arrays: out_summary_p for
[P(Y=1|T=i)...] and out_summary_n for [N(T=i)...], instead of the
previous list of list.
for all the evaluation functions, created the arr_evaluate_*
versions that uses the new node summary format. Also created
arr_normI as the counter-part of normI using the new node summary
format.
added some cdef to give type declarations to help speed up some
calculations.
Modifcation version 3, on 2023-10-06 by Peter Lo peterloleungyau@gmail.com
combine divideSet_len and group_uniqueCounts_to_arr to be
group_counts_by_divide, so as to reduce creating intermediate
objects. This calculates the group counts for the left branch.
created tree_node_summary_from_counts from tree_node_summary_to_arr,
to use pre-calculated group counts (e.g. by group_counts_by_divide).
for right branch, calculate the group counts by subtracting the
group counts of left branch from the total count (pre-calculated
outside the looping of choosing split points), which should be more
efficient than looping through the data again.
Types of changes
What types of changes does your code introduce to CausalML?
Put an
x
in the boxes that applyChecklist
Put an
x
in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.Further comments
If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc. This PR template is adopted from appium.