Skip to content

Commit

Permalink
Multiclass v2 (#264)
Browse files Browse the repository at this point in the history
* model page works on multiclass

* publish

* aggregate features weighted

* dependence plot weighted

* What if feature importance mc

* ICE plot multiclass

* tooltip start

* tooltips

* dependence info text

* what if class callout

* allow custom categorical values in whatif

* fix search bug

* better number editing textbox

* linting

* support for just global data

* comments

* error check

* lint
  • Loading branch information
rihorn2 authored Jun 24, 2020
1 parent 7b6832d commit 9ab8817
Show file tree
Hide file tree
Showing 21 changed files with 1,153 additions and 278 deletions.
2 changes: 1 addition & 1 deletion visualization/dashboard/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "interpret-dashboard",
"version": "0.1.9-beta1",
"version": "0.1.9-beta3",
"license": "See license file 'LICENSE'",
"description": "ML Chart Lib",
"main": "rel/index.js",
Expand Down
42 changes: 31 additions & 11 deletions visualization/dashboard/src/Localization/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@
"_predictedClassInfo.comment": "explains predicted class weight",
"enumeratedClassInfo": "Enumerated class names: Shows only the specified class's feature importance values across all data points.",
"_enumeratedClassInfo.comment": "explains the weights for selecting a single class",
"close": "Close"
"close": "Close",
"crossClassWeights": "Cross class weights"
},
"AggregateImportance": {
"scaledFeatureValue": "Scaled Feature Value",
Expand Down Expand Up @@ -268,7 +269,14 @@
"aggregateFeatureImportance": "Aggregate Feature Importance",
"_aggregateFeatureImportance.comment": "graph label for aggregated (summed and averaged) feature importances",
"missingParameters": "This tab requires the local feature importance parameter be supplied.",
"_missingPArameters.comment": "Show a message if the required feature importance parameter is not provided"
"_missingParameters.comment": "Show a message if the required feature importance parameter is not provided",
"weightOptions": "Class importance weights",
"_weightOptions.comment": "Weight how importance values are averaged https://en.wikipedia.org/wiki/Weighted_arithmetic_mean",
"dependencePlotPrompt": "How to read this chart",
"dependencePlotTitle": "Dependence Plots",
"dependencePlotHelperText": "This dependence plot shows the relationship between the value of a feature to the corresponding importance of the feature across a cohort.",
"dependencePlotFeatureSelectPlaceholder": "Select feature",
"datasetRequired": "Dependence plots require the evaluation dataset and local feature importance array."
},
"CohortBanner": {
"dataStatistics": "Data Statistics",
Expand Down Expand Up @@ -391,21 +399,21 @@
"_whatIfNameLabel.comment": "label above text field where user can name their what-if hypothetical point",
"featureValues": "Feature values",
"_featureValues.comment": "header above the list of feature names (column names)",
"predictedClass": "Predicted class: {0}",
"predictedClass": "Predicted class: ",
"_predictedClass.comment": "the predicted class for a row",
"predictedValue": "Predicted value: {0}",
"predictedValue": "Predicted value: ",
"_predictedValue.comment": "the predicted value for a row",
"probability": "Probability: {0}",
"probability": "Probability: ",
"_probability.comment": "the probability that the predicted class is correct",
"trueClass": "True class: {0}",
"trueClass": "True class: ",
"_trueClass.comment": "prefix to actual label",
"trueValue": "True value: {0}",
"trueValue": "True value: ",
"trueValue.comment": "prefix to actual label for regression",
"newPredictedClass": "New predicted class: {0}",
"newPredictedClass": "New predicted class: ",
"_newPredictedClass.comment": "the prediction after the user changed features",
"newPredictedValue": "New predicted value: {0}",
"newPredictedValue": "New predicted value: ",
"_newPredictedValue.comment": "the prediction after the user changed features",
"newProbability": "New probability: {0}",
"newProbability": "New probability: ",
"_newProbability.comment": "the probability for the new prediction",
"saveAsNewPoint": "Save as new point",
"_saveAsNewPoint.comment": "button to save hypothetical point",
Expand All @@ -426,7 +434,16 @@
"missingParameters": "This tab requires an evaluation dataset be supplied.",
"_missingParameters.comment": "Show a message if the required dataset parameter is not provided",
"selectionLimit": "Maximum of 3 selected points",
"_selectionLimit.comment": "A user can only select 3 points from a chart at a time, this message is displayed if they click a 4th"
"_selectionLimit.comment": "A user can only select 3 points from a chart at a time, this message is displayed if they click a 4th",
"classPickerLabel": "Class",
"tooltipTitleMany": "Top {0} predicted classes",
"_tooltipTitleMany.comment": "placeholder is the number of classes shown",
"whatIfTooltipTitle": "What-If predicted classes",
"tooltipTitleFew": "Predicted classes",
"probabilityLabel": "Probability",
"deltaLabel": "Delta",
"_deltaLabel.comment": "represents the change in a value",
"nonNumericValue": "Value should be numeric"
},
"CohortEditor": {
"selectFilter": "Select Filter",
Expand Down Expand Up @@ -518,5 +535,8 @@
"_fpr.comment": "False positive rate, see https://en.wikipedia.org/wiki/Evaluation_of_binary_classifiers",
"fnr": "FNR: {0}",
"_fnr.comment": "False negative rate, see https://en.wikipedia.org/wiki/Evaluation_of_binary_classifiers"
},
"GlobalOnlyChart": {
"helperText": "Explore the top k important features that impact your overall model predictions. Use the slider to show descending feature importances."
}
}
6 changes: 5 additions & 1 deletion visualization/dashboard/src/MLIDashboard/Cohort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,14 @@ export class Cohort {
return this.cachedTransposedLocalFeatureImportances;
}

private applyFilters(): void {
public clearCachedImportances(): void {
this.cachedAverageImportance = undefined;
this.cachedTransposedLocalFeatureImportances = undefined;
this.mutateCount += 1;
}

private applyFilters(): void {
this.clearCachedImportances();
this.filteredData = this.jointDataset.dataDict.filter((row) =>
this.filters.every((filter) => {
const rowVal = row[filter.column];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export class CohortList extends React.PureComponent<ICohortListProps> {
root: classNames.commandButton,
menuIcon: classNames.menuIcon,
}}
disabled={this.props.jointDataset.dataDict.length === 0}
menuIconProps={{ iconName: 'More' }}
menuProps={{
items: [
Expand Down Expand Up @@ -102,6 +103,7 @@ export class CohortList extends React.PureComponent<ICohortListProps> {
);
})}
<PrimaryButton
disabled={this.props.jointDataset.dataDict.length === 0}
onClick={this.props.editCohort.bind(this, this.props.cohorts.length)}
text={localization.CohortBanner.addCohort}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,16 +154,12 @@ export const dastasetExplorerTabStyles: () => IProcessedStyleSet<IDatasetExplore
padding: '10px 20px',
backgroundColor: theme.semanticColors.bodyBackground,
},
chartEditorButton: {
color: theme.semanticColors.buttonText,
backgroundColor: theme.semanticColors.buttonBackground,
borderWidth: '1px',
borderStyle: 'solid',
borderColor: theme.semanticColors.buttonBorder,
position: 'absolute',
right: '10px',
zIndex: 10,
},
chartEditorButton: [
FabricStyles.chartEditorButton,
{
right: '10px',
},
],
missingParametersPlaceholder: [FabricStyles.missingParameterPlaceholder],
missingParametersPlaceholderSpacer: [FabricStyles.missingParameterPlaceholderSpacer],
faintText: [FabricStyles.faintText],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@ import { Cohort } from '../../Cohort';
import { Text } from 'office-ui-fabric-react';
import { FabricStyles } from '../../FabricStyles';
import { dependencePlotStyles } from './DependencePlot.styles';
import { WeightVectorOption } from '../../IWeightedDropdownContext';

export interface IDependecePlotProps {
chartProps: IGenericChartProps;
jointDataset: JointDataset;
cohort: Cohort;
cohortIndex: number;
metadata: IExplanationModelMetadata;
selectedWeight: WeightVectorOption;
selectedWeightLabel: string;
onChange: (props: IGenericChartProps) => void;
}

Expand Down Expand Up @@ -88,7 +91,7 @@ export class DependencePlot extends React.PureComponent<IDependecePlotProps> {
? this.props.jointDataset.metaDict[this.props.chartProps.xAxis.property].label
: this.props.jointDataset.metaDict[this.props.chartProps.xAxis.property].label +
' : ' +
this.props.metadata.classNames[0];
this.props.selectedWeightLabel;
return (
<div className={classNames.DependencePlot}>
<div className={classNames.chartWithAxes}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ export class FeatureImportanceBar extends React.PureComponent<IFeatureBarProps,
}

private selectPointFromChart(data: any): void {
if (this.props.onFeatureSelection === undefined) {
return;
}
const trace = data.points[0];
const featureNumber = this.props.sortArray[trace.x];
this.props.onFeatureSelection(trace.curveNumber, featureNumber);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ export interface IGlobalTabStyles {
chartEditorButton: IStyle;
callout: IStyle;
boldText: IStyle;
calloutWrapper: IStyle;
calloutHeader: IStyle;
calloutTitle: IStyle;
calloutInner: IStyle;
dependencePlotInfoButton: IStyle;
multiclassWeightLabel: IStyle;
multiclassWeightLabelText: IStyle;
cohortLegendWithTop: IStyle;
}

export const globalTabStyles: () => IProcessedStyleSet<IGlobalTabStyles> = () => {
Expand Down Expand Up @@ -96,16 +104,12 @@ export const globalTabStyles: () => IProcessedStyleSet<IGlobalTabStyles> = () =>
missingParametersPlaceholder: [FabricStyles.missingParameterPlaceholder],
missingParametersPlaceholderSpacer: [FabricStyles.missingParameterPlaceholderSpacer],
faintText: [FabricStyles.faintText],
chartEditorButton: {
color: theme.semanticColors.buttonText,
backgroundColor: theme.semanticColors.buttonBackground,
borderWidth: '1px',
borderStyle: 'solid',
borderColor: theme.semanticColors.buttonBorder,
position: 'absolute',
right: '210px',
zIndex: 10,
},
chartEditorButton: [
FabricStyles.chartEditorButton,
{
right: '210px',
},
],
callout: {
width: '200px',
boxSizing: 'border-box',
Expand All @@ -118,5 +122,27 @@ export const globalTabStyles: () => IProcessedStyleSet<IGlobalTabStyles> = () =>
fontWeight: '600',
paddingBottom: '5px',
},
calloutWrapper: [FabricStyles.calloutWrapper],
calloutHeader: [FabricStyles.calloutHeader],
calloutTitle: [FabricStyles.calloutTitle],
calloutInner: [FabricStyles.calloutInner],
dependencePlotInfoButton: {
width: 'fit-content',
margin: '5px 200px 5px auto',
padding: '10px',
},
multiclassWeightLabel: {
display: 'inline-flex',
paddingTop: '10px',
},
multiclassWeightLabelText: {
paddingTop: '5px',
fontWeight: '600',
},
cohortLegendWithTop: {
fontWeight: '600',
paddingBottom: '10px',
paddingTop: '10px',
},
});
};
Loading

0 comments on commit 9ab8817

Please sign in to comment.