MilesCranmer commited on
Commit
c8dffac
1 Parent(s): eb96ede

Enable custom complexities

Browse files
Files changed (2) hide show
  1. pysr/sr.py +30 -1
  2. pysr/version.py +2 -2
pysr/sr.py CHANGED
@@ -357,6 +357,9 @@ class PySRRegressor(BaseEstimator, RegressorMixin):
357
  unary_operators=None,
358
  procs=cpu_count(),
359
  loss="L2DistLoss()",
 
 
 
360
  populations=15,
361
  niterations=40,
362
  ncyclesperiteration=550,
@@ -444,6 +447,17 @@ class PySRRegressor(BaseEstimator, RegressorMixin):
444
  :type populations: int
445
  :param loss: String of Julia code specifying the loss function. Can either be a loss from LossFunctions.jl, or your own loss written as a function. Examples of custom written losses include: `myloss(x, y) = abs(x-y)` for non-weighted, or `myloss(x, y, w) = w*abs(x-y)` for weighted. Among the included losses, these are as follows. Regression: `LPDistLoss{P}()`, `L1DistLoss()`, `L2DistLoss()` (mean square), `LogitDistLoss()`, `HuberLoss(d)`, `L1EpsilonInsLoss(ϵ)`, `L2EpsilonInsLoss(ϵ)`, `PeriodicLoss(c)`, `QuantileLoss(τ)`. Classification: `ZeroOneLoss()`, `PerceptronLoss()`, `L1HingeLoss()`, `SmoothedL1HingeLoss(γ)`, `ModifiedHuberLoss()`, `L2MarginLoss()`, `ExpLoss()`, `SigmoidLoss()`, `DWDMarginLoss(q)`.
446
  :type loss: str
 
 
 
 
 
 
 
 
 
 
 
447
  :param denoise: Whether to use a Gaussian Process to denoise the data before inputting to PySR. Can help PySR fit noisy data.
448
  :type denoise: bool
449
  :param select_k_features: whether to run feature selection in Python using random forests, before passing to the symbolic regression code. None means no feature selection; an int means select that many features.
@@ -697,6 +711,9 @@ class PySRRegressor(BaseEstimator, RegressorMixin):
697
  unary_operators=unary_operators,
698
  procs=procs,
699
  loss=loss,
 
 
 
700
  populations=populations,
701
  niterations=niterations,
702
  ncyclesperiteration=ncyclesperiteration,
@@ -1227,8 +1244,8 @@ class PySRRegressor(BaseEstimator, RegressorMixin):
1227
  Main.div = Main.eval("(/)")
1228
 
1229
  nested_constraints = self.params["nested_constraints"]
 
1230
  if nested_constraints is not None:
1231
- # Parse dict into Julia Dict:
1232
  nested_constraints_str = "Dict("
1233
  for outer_k, outer_v in nested_constraints.items():
1234
  nested_constraints_str += f"({outer_k}) => Dict("
@@ -1238,6 +1255,15 @@ class PySRRegressor(BaseEstimator, RegressorMixin):
1238
  nested_constraints_str += ")"
1239
  nested_constraints = Main.eval(nested_constraints_str)
1240
 
 
 
 
 
 
 
 
 
 
1241
  Main.custom_loss = Main.eval(loss)
1242
 
1243
  mutationWeights = [
@@ -1288,6 +1314,9 @@ class PySRRegressor(BaseEstimator, RegressorMixin):
1288
  unary_operators=Main.eval(str(tuple(unary_operators)).replace("'", "")),
1289
  bin_constraints=bin_constraints,
1290
  una_constraints=una_constraints,
 
 
 
1291
  nested_constraints=nested_constraints,
1292
  loss=Main.custom_loss,
1293
  maxsize=int(maxsize),
 
357
  unary_operators=None,
358
  procs=cpu_count(),
359
  loss="L2DistLoss()",
360
+ complexity_of_operators=None,
361
+ complexity_of_constants=None,
362
+ complexity_of_variables=None,
363
  populations=15,
364
  niterations=40,
365
  ncyclesperiteration=550,
 
447
  :type populations: int
448
  :param loss: String of Julia code specifying the loss function. Can either be a loss from LossFunctions.jl, or your own loss written as a function. Examples of custom written losses include: `myloss(x, y) = abs(x-y)` for non-weighted, or `myloss(x, y, w) = w*abs(x-y)` for weighted. Among the included losses, these are as follows. Regression: `LPDistLoss{P}()`, `L1DistLoss()`, `L2DistLoss()` (mean square), `LogitDistLoss()`, `HuberLoss(d)`, `L1EpsilonInsLoss(ϵ)`, `L2EpsilonInsLoss(ϵ)`, `PeriodicLoss(c)`, `QuantileLoss(τ)`. Classification: `ZeroOneLoss()`, `PerceptronLoss()`, `L1HingeLoss()`, `SmoothedL1HingeLoss(γ)`, `ModifiedHuberLoss()`, `L2MarginLoss()`, `ExpLoss()`, `SigmoidLoss()`, `DWDMarginLoss(q)`.
449
  :type loss: str
450
+ :param complexity_of_operators: If you would like to use a complexity other than 1 for
451
+ an operator, specify the complexity here. For example, `{"sin": 2, "+": 1}` would give
452
+ a complexity of 2 for each use of the `sin` operator, and a complexity of 1
453
+ for each use of the `+` operator (which is the default). You may specify
454
+ real numbers for a complexity, and the total complexity of a tree will be rounded
455
+ to the nearest integer after computing.
456
+ :type complexity_of_operators: dict
457
+ :param complexity_of_constants: Complexity of constants. Default is 1.
458
+ :type complexity_of_constants: int/float
459
+ :param complexity_of_variables: Complexity of variables. Default is 1.
460
+ :type complexity_of_variables: int/float
461
  :param denoise: Whether to use a Gaussian Process to denoise the data before inputting to PySR. Can help PySR fit noisy data.
462
  :type denoise: bool
463
  :param select_k_features: whether to run feature selection in Python using random forests, before passing to the symbolic regression code. None means no feature selection; an int means select that many features.
 
711
  unary_operators=unary_operators,
712
  procs=procs,
713
  loss=loss,
714
+ complexity_of_operators=complexity_of_operators,
715
+ complexity_of_constants=complexity_of_constants,
716
+ complexity_of_variables=complexity_of_variables,
717
  populations=populations,
718
  niterations=niterations,
719
  ncyclesperiteration=ncyclesperiteration,
 
1244
  Main.div = Main.eval("(/)")
1245
 
1246
  nested_constraints = self.params["nested_constraints"]
1247
+ # Parse dict into Julia Dict for nested constraints::
1248
  if nested_constraints is not None:
 
1249
  nested_constraints_str = "Dict("
1250
  for outer_k, outer_v in nested_constraints.items():
1251
  nested_constraints_str += f"({outer_k}) => Dict("
 
1255
  nested_constraints_str += ")"
1256
  nested_constraints = Main.eval(nested_constraints_str)
1257
 
1258
+ # Parse dict into Julia Dict for complexities:
1259
+ complexity_of_operators = self.params["complexity_of_operators"]
1260
+ if complexity_of_operators is not None:
1261
+ complexity_of_operators_str = "Dict("
1262
+ for k, v in complexity_of_operators.items():
1263
+ complexity_of_operators_str += f"({k}) => {v}, "
1264
+ complexity_of_operators_str += ")"
1265
+ complexity_of_operators = Main.eval(complexity_of_operators_str)
1266
+
1267
  Main.custom_loss = Main.eval(loss)
1268
 
1269
  mutationWeights = [
 
1314
  unary_operators=Main.eval(str(tuple(unary_operators)).replace("'", "")),
1315
  bin_constraints=bin_constraints,
1316
  una_constraints=una_constraints,
1317
+ complexity_of_operators=complexity_of_operators,
1318
+ complexity_of_constants=self.params["complexity_of_constants"],
1319
+ complexity_of_variables=self.params["complexity_of_variables"],
1320
  nested_constraints=nested_constraints,
1321
  loss=Main.custom_loss,
1322
  maxsize=int(maxsize),
pysr/version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "0.8.4"
2
- __symbolic_regression_jl_version__ = "0.9.1"
 
1
+ __version__ = "0.8.5"
2
+ __symbolic_regression_jl_version__ = "0.9.2"