|
| 1 | +from uuid import UUID |
| 2 | + |
| 3 | +from citrine._rest.resource import Resource |
| 4 | +from citrine._serialization import properties |
| 5 | + |
| 6 | + |
| 7 | +class ShapleyMaterial(Resource): |
| 8 | + """The feature effect of a material.""" |
| 9 | + |
| 10 | + material_id = properties.UUID('material_id', serializable=False) |
| 11 | + value = properties.Float('value', serializable=False) |
| 12 | + |
| 13 | + |
| 14 | +class ShapleyFeature(Resource): |
| 15 | + """All feature effects for this feature by material.""" |
| 16 | + |
| 17 | + feature = properties.String('feature', serializable=False) |
| 18 | + materials = properties.List(properties.Object(ShapleyMaterial), 'materials', |
| 19 | + serializable=False) |
| 20 | + |
| 21 | + @property |
| 22 | + def material_dict(self) -> dict[UUID, float]: |
| 23 | + """Presents the feature's effects as a dictionary by material.""" |
| 24 | + return {material.material_id: material.value for material in self.materials} |
| 25 | + |
| 26 | + |
| 27 | +class ShapleyOutput(Resource): |
| 28 | + """All feature effects for this output by feature.""" |
| 29 | + |
| 30 | + output = properties.String('output', serializable=False) |
| 31 | + features = properties.List(properties.Object(ShapleyFeature), 'features', serializable=False) |
| 32 | + |
| 33 | + @property |
| 34 | + def feature_dict(self) -> dict[str, dict[UUID, float]]: |
| 35 | + """Presents the output's feature effects as a dictionary by feature.""" |
| 36 | + return {feature.feature: feature.material_dict for feature in self.features} |
| 37 | + |
| 38 | + |
| 39 | +class FeatureEffects(Resource): |
| 40 | + """Captures information about the feature effects associated with a predictor.""" |
| 41 | + |
| 42 | + predictor_id = properties.UUID('metadata.predictor_id', serializable=False) |
| 43 | + predictor_version = properties.Integer('metadata.predictor_version', serializable=False) |
| 44 | + status = properties.String('metadata.status', serializable=False) |
| 45 | + failure_reason = properties.Optional(properties.String(), 'metadata.failure_reason', |
| 46 | + serializable=False) |
| 47 | + |
| 48 | + outputs = properties.List(properties.Object(ShapleyOutput), 'resultobj', serializable=False) |
| 49 | + |
| 50 | + @classmethod |
| 51 | + def _pre_build(cls, data: dict) -> dict: |
| 52 | + shapley = data["result"] |
| 53 | + material_ids = shapley["materials"] |
| 54 | + |
| 55 | + outputs = [] |
| 56 | + for output, feature_dict in shapley["outputs"].items(): |
| 57 | + features = [] |
| 58 | + for feature, values in feature_dict.items(): |
| 59 | + items = zip(material_ids, values) |
| 60 | + materials = [{"material_id": mid, "value": value} for mid, value in items] |
| 61 | + features.append({ |
| 62 | + "feature": feature, |
| 63 | + "materials": materials |
| 64 | + }) |
| 65 | + |
| 66 | + outputs.append({"output": output, "features": features}) |
| 67 | + |
| 68 | + data["resultobj"] = outputs |
| 69 | + return data |
| 70 | + |
| 71 | + @property |
| 72 | + def as_dict(self) -> dict[str, dict[str, dict[UUID, float]]]: |
| 73 | + """Presents the feature effects as a dictionary by output.""" |
| 74 | + return {output.output: output.feature_dict for output in self.outputs} |
0 commit comments