ltfmselector 0.1.12__py3-none-any.whl → 0.2.0__py3-none-any.whl
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.
- ltfmselector/env.py +63 -2
- ltfmselector/ltfmselector.py +66 -5
- {ltfmselector-0.1.12.dist-info → ltfmselector-0.2.0.dist-info}/METADATA +1 -1
- ltfmselector-0.2.0.dist-info/RECORD +9 -0
- ltfmselector-0.1.12.dist-info/RECORD +0 -9
- {ltfmselector-0.1.12.dist-info → ltfmselector-0.2.0.dist-info}/WHEEL +0 -0
- {ltfmselector-0.1.12.dist-info → ltfmselector-0.2.0.dist-info}/licenses/LICENSE +0 -0
ltfmselector/env.py
CHANGED
|
@@ -14,7 +14,10 @@ capLowerValues = lambda x: 0.0 if x < 0.0 else x
|
|
|
14
14
|
|
|
15
15
|
class Environment:
|
|
16
16
|
def __init__(
|
|
17
|
-
self, X, y, X_bg,
|
|
17
|
+
self, X, y, X_bg,
|
|
18
|
+
fQueryCost, fQueryFunction,
|
|
19
|
+
fThreshold, fCap, fRate,
|
|
20
|
+
mQueryCost,
|
|
18
21
|
fRepeatQueryCost, p_wNoFCost, errorCost, pType,
|
|
19
22
|
regression_tol, regression_error_rounding, pModels, device,
|
|
20
23
|
sample_weight=None, **kwargs
|
|
@@ -42,6 +45,21 @@ class Environment:
|
|
|
42
45
|
fQueryCost : float
|
|
43
46
|
Cost of querying a feature
|
|
44
47
|
|
|
48
|
+
fQueryFunction : None or {'step', 'linear', 'quadratic', 'exponential'}
|
|
49
|
+
Function to progressively increase cost of recruiting a feature
|
|
50
|
+
|
|
51
|
+
fThreshold : None or int
|
|
52
|
+
If `fQueryFunction == {'step', 'linear', 'quadratic', 'exponential'}`
|
|
53
|
+
Threshold of number of features, before cost of recruiting
|
|
54
|
+
increases
|
|
55
|
+
|
|
56
|
+
fCap : None or float
|
|
57
|
+
If `fQueryFunction == {'step'}`, upper limit of penalty
|
|
58
|
+
|
|
59
|
+
fRate : None or float
|
|
60
|
+
If `fQueryFunction == {'linear', 'quadratic', 'exponential'}`, rate
|
|
61
|
+
individual cost functions
|
|
62
|
+
|
|
45
63
|
mQueryCost : float
|
|
46
64
|
Cost of querying a prediction model
|
|
47
65
|
|
|
@@ -87,6 +105,11 @@ class Environment:
|
|
|
87
105
|
|
|
88
106
|
# Reward functions
|
|
89
107
|
self.fQueryCost = fQueryCost
|
|
108
|
+
self.fQueryFunction = fQueryFunction
|
|
109
|
+
self.fThreshold = fThreshold
|
|
110
|
+
self.fCap = fCap
|
|
111
|
+
self.fRate = fRate
|
|
112
|
+
|
|
90
113
|
self.mQueryCost = mQueryCost
|
|
91
114
|
self.fRepeatQueryCost = fRepeatQueryCost
|
|
92
115
|
self.p_wNoFCost = p_wNoFCost
|
|
@@ -204,7 +227,7 @@ class Environment:
|
|
|
204
227
|
self.state[action] = self.X_test.iloc[0, action]
|
|
205
228
|
|
|
206
229
|
# Punish for querying a feature
|
|
207
|
-
return [self.state, -self.
|
|
230
|
+
return [self.state, -self.get_fQueryCost(), False]
|
|
208
231
|
|
|
209
232
|
# Punish agent for attempting to query a feature already
|
|
210
233
|
# previously selected
|
|
@@ -331,6 +354,44 @@ class Environment:
|
|
|
331
354
|
|
|
332
355
|
return [None, 0.0, True]
|
|
333
356
|
|
|
357
|
+
def get_fQueryCost(self):
|
|
358
|
+
'''
|
|
359
|
+
Get cost of querying a feature
|
|
360
|
+
'''
|
|
361
|
+
if self.fQueryFunction is None:
|
|
362
|
+
return self.fQueryCost
|
|
363
|
+
|
|
364
|
+
# Get number of total recruited features
|
|
365
|
+
nFSubset = (self.get_feature_mask()).sum()
|
|
366
|
+
|
|
367
|
+
if self.fQueryFunction == "step":
|
|
368
|
+
return self.get_fQueryCostStep(nFSubset)
|
|
369
|
+
elif self.fQueryFunction == "linear":
|
|
370
|
+
return self.get_fQueryCostLinear(nFSubset)
|
|
371
|
+
elif self.fQueryFunction == "quadratic":
|
|
372
|
+
return self.get_fQueryCostQuadratic(nFSubset)
|
|
373
|
+
|
|
374
|
+
def get_fQueryCostStep(self, _nFSubset):
|
|
375
|
+
'''Step function for querying feature'''
|
|
376
|
+
if _nFSubset > self.fThreshold:
|
|
377
|
+
return self.fCap
|
|
378
|
+
else:
|
|
379
|
+
return self.fQueryCost
|
|
380
|
+
|
|
381
|
+
def get_fQueryCostLinear(self, _nFSubset):
|
|
382
|
+
'''Linear function for querying feature'''
|
|
383
|
+
return max(
|
|
384
|
+
self.fQueryCost,
|
|
385
|
+
self.fQueryCost + self.fRate*(_nFSubset-self.fThreshold)
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
def get_fQueryCostQuadratic(self, _nFSubset):
|
|
389
|
+
'''Quadratic function for querying feature'''
|
|
390
|
+
if _nFSubset > self.fThreshold:
|
|
391
|
+
return self.fQueryCost + self.fRate*(_nFSubset-self.fThreshold)**2
|
|
392
|
+
else:
|
|
393
|
+
return self.fQueryCost
|
|
394
|
+
|
|
334
395
|
def get_feature_mask(self):
|
|
335
396
|
'''
|
|
336
397
|
Get the (boolean) feature mask that indicates if a feature has
|
ltfmselector/ltfmselector.py
CHANGED
|
@@ -72,7 +72,9 @@ class LTFMSelector:
|
|
|
72
72
|
def __init__(
|
|
73
73
|
self, episodes, batch_size=256, tau=0.0005,
|
|
74
74
|
eps_start=0.9, eps_end=0.05, eps_decay=1000,
|
|
75
|
-
fQueryCost=0.01,
|
|
75
|
+
fQueryCost=0.01, fQueryFunction=None,
|
|
76
|
+
fThreshold=None, fCap=None, fRate=None,
|
|
77
|
+
mQueryCost=0.01,
|
|
76
78
|
fRepeatQueryCost=1.0, p_wNoFCost=5.0, errorCost=1.0,
|
|
77
79
|
pType="regression", regression_tol=0.5,
|
|
78
80
|
regression_error_rounding=1,
|
|
@@ -105,7 +107,32 @@ class LTFMSelector:
|
|
|
105
107
|
Rate of exponential decay
|
|
106
108
|
|
|
107
109
|
fQueryCost : float
|
|
108
|
-
Cost of querying a feature
|
|
110
|
+
Cost of querying a feature.
|
|
111
|
+
|
|
112
|
+
fQueryFunction : None or {'step', 'linear', 'quadratic'}
|
|
113
|
+
User can also decide to progressively increase the cost of
|
|
114
|
+
querying features in the following manner:
|
|
115
|
+
'step' :
|
|
116
|
+
Every additional feature adds a fixed constant, determined
|
|
117
|
+
by user.
|
|
118
|
+
'linear' :
|
|
119
|
+
Cost of every additional feature linearly increases according
|
|
120
|
+
to user-defined gradient
|
|
121
|
+
'quadratic' :
|
|
122
|
+
Cost of every additional feature increases quadratically,
|
|
123
|
+
according to a user-defined rate
|
|
124
|
+
|
|
125
|
+
fThreshold : None or int
|
|
126
|
+
If `fQueryFunction == {'step', 'linear', 'quadratic', 'exponential'}`
|
|
127
|
+
Threshold of number of features, before cost of recruiting
|
|
128
|
+
increases
|
|
129
|
+
|
|
130
|
+
fCap : None or float
|
|
131
|
+
If `fQueryFunction == {'step'}`, upper limit of penalty
|
|
132
|
+
|
|
133
|
+
fRate : None or float
|
|
134
|
+
If `fQueryFunction == {'linear', 'quadratic', 'exponential'}`, rate
|
|
135
|
+
individual cost functions
|
|
109
136
|
|
|
110
137
|
mQueryCost : float
|
|
111
138
|
Cost of querying a prediction model
|
|
@@ -196,6 +223,35 @@ class LTFMSelector:
|
|
|
196
223
|
|
|
197
224
|
# Reward function
|
|
198
225
|
self.fQueryCost = fQueryCost
|
|
226
|
+
self.fQueryFunction = fQueryFunction
|
|
227
|
+
self.fThreshold = fThreshold
|
|
228
|
+
self.fCap = fCap
|
|
229
|
+
self.fRate = fRate
|
|
230
|
+
|
|
231
|
+
# Options for progressive cost functions
|
|
232
|
+
if isinstance(self.fQueryFunction, str):
|
|
233
|
+
fQueryFunctions = ['step', 'linear', 'quadratic']
|
|
234
|
+
if not self.fQueryFunction in fQueryFunctions:
|
|
235
|
+
raise ValueError(
|
|
236
|
+
f"{self.fQueryFunction} is not a valid option. Available " +
|
|
237
|
+
f"options are {fQueryFunctions}"
|
|
238
|
+
)
|
|
239
|
+
else:
|
|
240
|
+
if not isinstance(fThreshold, int):
|
|
241
|
+
raise ValueError("Parameter fThreshold must be an integer!")
|
|
242
|
+
|
|
243
|
+
if self.fQueryFunction == "step":
|
|
244
|
+
if not (isinstance(fCap, float) or isinstance(fCap, int)):
|
|
245
|
+
raise ValueError("Parameter fCap must be an int or float!")
|
|
246
|
+
else:
|
|
247
|
+
self.fCap = float(fCap)
|
|
248
|
+
else:
|
|
249
|
+
if self.fQueryFunction in ["linear", "quadratic"]:
|
|
250
|
+
if not (isinstance(fRate, float) or isinstance(fRate, int)):
|
|
251
|
+
raise ValueError("Parameter fRate must be an int or float!")
|
|
252
|
+
else:
|
|
253
|
+
self.fRate = float(fRate)
|
|
254
|
+
|
|
199
255
|
self.mQueryCost = mQueryCost
|
|
200
256
|
self.fRepeatQueryCost = fRepeatQueryCost
|
|
201
257
|
self.p_wNoFCost = p_wNoFCost
|
|
@@ -327,7 +383,7 @@ class LTFMSelector:
|
|
|
327
383
|
# If user wants to save average computed action-value functions and
|
|
328
384
|
# rewards of sampled batches
|
|
329
385
|
if returnQ:
|
|
330
|
-
total_iterations =
|
|
386
|
+
total_iterations = 16777216 # 2^24
|
|
331
387
|
LearningValuesMatrix = np.zeros(
|
|
332
388
|
(total_iterations, 3), dtype=np.float32
|
|
333
389
|
)
|
|
@@ -336,7 +392,9 @@ class LTFMSelector:
|
|
|
336
392
|
# Initializing the environment
|
|
337
393
|
env = Environment(
|
|
338
394
|
self.X, self.y, self.background_dataset,
|
|
339
|
-
self.fQueryCost, self.
|
|
395
|
+
self.fQueryCost, self.fQueryFunction,
|
|
396
|
+
self.fThreshold, self.fCap, self.fRate,
|
|
397
|
+
self.mQueryCost,
|
|
340
398
|
self.fRepeatQueryCost, self.p_wNoFCost, self.errorCost,
|
|
341
399
|
self.pType, self.regression_tol, self.regression_error_rounding,
|
|
342
400
|
self.pModels, self.device, sample_weight=self.sample_weight,
|
|
@@ -484,6 +542,7 @@ class LTFMSelector:
|
|
|
484
542
|
writer.add_scalar("Metrics/Average_QValue", _res[0], monitor_count)
|
|
485
543
|
writer.add_scalar("Metrics/Average_Reward", _res[1], monitor_count)
|
|
486
544
|
writer.add_scalar("Metrics/Average_Target", _res[2], monitor_count)
|
|
545
|
+
writer.flush()
|
|
487
546
|
writer.close()
|
|
488
547
|
|
|
489
548
|
if returnQ:
|
|
@@ -517,7 +576,9 @@ class LTFMSelector:
|
|
|
517
576
|
# Initializing the environment
|
|
518
577
|
env = Environment(
|
|
519
578
|
self.X, self.y, self.background_dataset,
|
|
520
|
-
self.fQueryCost, self.
|
|
579
|
+
self.fQueryCost, self.fQueryFunction,
|
|
580
|
+
self.fThreshold, self.fCap, self.fRate,
|
|
581
|
+
self.mQueryCost,
|
|
521
582
|
self.fRepeatQueryCost, self.p_wNoFCost, self.errorCost,
|
|
522
583
|
self.pType, self.regression_tol, self.regression_error_rounding,
|
|
523
584
|
self.pModels, self.device, **kwargs
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
ltfmselector/__init__.py,sha256=lf3e90CNpEDvEmNZ-0iuoHOPsA7D-WN_opbBsTYLVEA,76
|
|
2
|
+
ltfmselector/env.py,sha256=898o_g6-i0Rz5R-4WxZInf3xaxXHf58kPJId0KeewQM,16070
|
|
3
|
+
ltfmselector/ltfmselector.py,sha256=zxGTLtuaoqdWbGxM8JmQES1_kGpNad1utRfDkepPoko,32329
|
|
4
|
+
ltfmselector/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
ltfmselector/utils.py,sha256=VXYZSDm7x4s0p9F_58NLW8WQa3dxi0vHZewRy6miC2E,5438
|
|
6
|
+
ltfmselector-0.2.0.dist-info/METADATA,sha256=76QDgOBLL81otMAwr9D-eNfviT5SY76Tf70-WNGIgyg,3020
|
|
7
|
+
ltfmselector-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
8
|
+
ltfmselector-0.2.0.dist-info/licenses/LICENSE,sha256=tmIDlkkp4a0EudXuGmeTdGjHjPhmmXkEMshACXLqX2w,1092
|
|
9
|
+
ltfmselector-0.2.0.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
ltfmselector/__init__.py,sha256=lf3e90CNpEDvEmNZ-0iuoHOPsA7D-WN_opbBsTYLVEA,76
|
|
2
|
-
ltfmselector/env.py,sha256=vizWGqDSc_2Zfs9aXjFARanIAz6PTKwUHu2_Lew9s3Y,13878
|
|
3
|
-
ltfmselector/ltfmselector.py,sha256=vs9unOmoDKq1piV6t87GC1wdy7kP8ucKHihw6i0F4KI,29567
|
|
4
|
-
ltfmselector/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
ltfmselector/utils.py,sha256=VXYZSDm7x4s0p9F_58NLW8WQa3dxi0vHZewRy6miC2E,5438
|
|
6
|
-
ltfmselector-0.1.12.dist-info/METADATA,sha256=QaUPeSx9NlZx0ZUbkEPRyFS-8nfJz9Y8yV5TXXPc7fA,3021
|
|
7
|
-
ltfmselector-0.1.12.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
8
|
-
ltfmselector-0.1.12.dist-info/licenses/LICENSE,sha256=tmIDlkkp4a0EudXuGmeTdGjHjPhmmXkEMshACXLqX2w,1092
|
|
9
|
-
ltfmselector-0.1.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|