[ML] DFAnalytics results: ensure ml result fields are shown in data grid (#68305)

* wip: ensure top classes and influencer result col show up correctly

* ensure ml subFields columns are populated
This commit is contained in:
Melissa Alvarez 2020-06-08 11:19:01 -04:00 committed by GitHub
parent bc3918671c
commit e2f11e9fe9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 43 additions and 7 deletions

View file

@ -29,6 +29,7 @@ import {
FEATURE_IMPORTANCE, FEATURE_IMPORTANCE,
FEATURE_INFLUENCE, FEATURE_INFLUENCE,
OUTLIER_SCORE, OUTLIER_SCORE,
TOP_CLASSES,
} from '../../data_frame_analytics/common/constants'; } from '../../data_frame_analytics/common/constants';
import { formatHumanReadableDateTimeSeconds } from '../../util/date_utils'; import { formatHumanReadableDateTimeSeconds } from '../../util/date_utils';
import { getNestedProperty } from '../../util/object_utils'; import { getNestedProperty } from '../../util/object_utils';
@ -110,7 +111,10 @@ export const getDataGridSchemasFromFieldTypes = (fieldTypes: FieldTypes, results
schema = 'numeric'; schema = 'numeric';
} }
if (field.includes(`${resultsField}.${FEATURE_IMPORTANCE}`)) { if (
field.includes(`${resultsField}.${FEATURE_IMPORTANCE}`) ||
field.includes(`${resultsField}.${TOP_CLASSES}`)
) {
schema = 'json'; schema = 'json';
} }

View file

@ -228,6 +228,16 @@ export const getPredictionFieldName = (
return predictionFieldName; return predictionFieldName;
}; };
export const getNumTopClasses = (
analysis: AnalysisConfig
): ClassificationAnalysis['classification']['num_top_classes'] => {
let numTopClasses;
if (isClassificationAnalysis(analysis) && analysis.classification.num_top_classes !== undefined) {
numTopClasses = analysis.classification.num_top_classes;
}
return numTopClasses;
};
export const getNumTopFeatureImportanceValues = ( export const getNumTopFeatureImportanceValues = (
analysis: AnalysisConfig analysis: AnalysisConfig
): ):

View file

@ -7,4 +7,5 @@
export const DEFAULT_RESULTS_FIELD = 'ml'; export const DEFAULT_RESULTS_FIELD = 'ml';
export const FEATURE_IMPORTANCE = 'feature_importance'; export const FEATURE_IMPORTANCE = 'feature_importance';
export const FEATURE_INFLUENCE = 'feature_influence'; export const FEATURE_INFLUENCE = 'feature_influence';
export const TOP_CLASSES = 'top_classes';
export const OUTLIER_SCORE = 'outlier_score'; export const OUTLIER_SCORE = 'outlier_score';

View file

@ -5,6 +5,7 @@
*/ */
import { import {
getNumTopClasses,
getNumTopFeatureImportanceValues, getNumTopFeatureImportanceValues,
getPredictedFieldName, getPredictedFieldName,
getDependentVar, getDependentVar,
@ -18,7 +19,7 @@ import { Field } from '../../../../common/types/fields';
import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../../../../../../src/plugins/data/public'; import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../../../../../../src/plugins/data/public';
import { newJobCapsService } from '../../services/new_job_capabilities_service'; import { newJobCapsService } from '../../services/new_job_capabilities_service';
import { FEATURE_IMPORTANCE, FEATURE_INFLUENCE, OUTLIER_SCORE } from './constants'; import { FEATURE_IMPORTANCE, FEATURE_INFLUENCE, OUTLIER_SCORE, TOP_CLASSES } from './constants';
export type EsId = string; export type EsId = string;
export type EsDocSource = Record<string, any>; export type EsDocSource = Record<string, any>;
@ -177,6 +178,7 @@ export const getDefaultFieldsFromJobCaps = (
const featureImportanceFields = []; const featureImportanceFields = [];
const featureInfluenceFields = []; const featureInfluenceFields = [];
const topClassesFields = [];
const allFields: any = []; const allFields: any = [];
let type: ES_FIELD_TYPES | undefined; let type: ES_FIELD_TYPES | undefined;
let predictedField: string | undefined; let predictedField: string | undefined;
@ -207,13 +209,14 @@ export const getDefaultFieldsFromJobCaps = (
type = newJobCapsService.getFieldById(dependentVariable)?.type; type = newJobCapsService.getFieldById(dependentVariable)?.type;
const predictionFieldName = getPredictionFieldName(jobConfig.analysis); const predictionFieldName = getPredictionFieldName(jobConfig.analysis);
const numTopFeatureImportanceValues = getNumTopFeatureImportanceValues(jobConfig.analysis); const numTopFeatureImportanceValues = getNumTopFeatureImportanceValues(jobConfig.analysis);
const numTopClasses = getNumTopClasses(jobConfig.analysis);
const defaultPredictionField = `${dependentVariable}_prediction`; const defaultPredictionField = `${dependentVariable}_prediction`;
predictedField = `${resultsField}.${ predictedField = `${resultsField}.${
predictionFieldName ? predictionFieldName : defaultPredictionField predictionFieldName ? predictionFieldName : defaultPredictionField
}`; }`;
if ((numTopFeatureImportanceValues ?? 0) > 0 && needsDestIndexFields === true) { if ((numTopFeatureImportanceValues ?? 0) > 0) {
featureImportanceFields.push({ featureImportanceFields.push({
id: `${resultsField}.${FEATURE_IMPORTANCE}`, id: `${resultsField}.${FEATURE_IMPORTANCE}`,
name: `${resultsField}.${FEATURE_IMPORTANCE}`, name: `${resultsField}.${FEATURE_IMPORTANCE}`,
@ -221,6 +224,14 @@ export const getDefaultFieldsFromJobCaps = (
}); });
} }
if ((numTopClasses ?? 0) > 0) {
topClassesFields.push({
id: `${resultsField}.${TOP_CLASSES}`,
name: `${resultsField}.${TOP_CLASSES}`,
type: KBN_FIELD_TYPES.UNKNOWN,
});
}
// Only need to add these fields if we didn't use dest index pattern to get the fields // Only need to add these fields if we didn't use dest index pattern to get the fields
if (needsDestIndexFields === true) { if (needsDestIndexFields === true) {
allFields.push( allFields.push(
@ -234,7 +245,12 @@ export const getDefaultFieldsFromJobCaps = (
} }
} }
allFields.push(...fields, ...featureImportanceFields, ...featureInfluenceFields); allFields.push(
...fields,
...featureImportanceFields,
...featureInfluenceFields,
...topClassesFields
);
allFields.sort(({ name: a }: { name: string }, { name: b }: { name: string }) => allFields.sort(({ name: a }: { name: string }, { name: b }: { name: string }) =>
sortExplorationResultsFields(a, b, jobConfig) sortExplorationResultsFields(a, b, jobConfig)
); );

View file

@ -19,7 +19,11 @@ import {
import { SavedSearchQuery } from '../../../../../contexts/ml'; import { SavedSearchQuery } from '../../../../../contexts/ml';
import { getIndexData, getIndexFields, DataFrameAnalyticsConfig } from '../../../../common'; import { getIndexData, getIndexFields, DataFrameAnalyticsConfig } from '../../../../common';
import { DEFAULT_RESULTS_FIELD, FEATURE_IMPORTANCE } from '../../../../common/constants'; import {
DEFAULT_RESULTS_FIELD,
FEATURE_IMPORTANCE,
TOP_CLASSES,
} from '../../../../common/constants';
import { sortExplorationResultsFields, ML__ID_COPY } from '../../../../common/fields'; import { sortExplorationResultsFields, ML__ID_COPY } from '../../../../common/fields';
export const useExplorationResults = ( export const useExplorationResults = (
@ -47,8 +51,9 @@ export const useExplorationResults = (
25, 25,
// reduce default selected rows from 20 to 8 for performance reasons. // reduce default selected rows from 20 to 8 for performance reasons.
8, 8,
// by default, hide feature-importance columns and the doc id copy // by default, hide feature-importance and top-classes columns and the doc id copy
(d) => !d.includes(`.${FEATURE_IMPORTANCE}.`) && d !== ML__ID_COPY (d) =>
!d.includes(`.${FEATURE_IMPORTANCE}.`) && !d.includes(`.${TOP_CLASSES}.`) && d !== ML__ID_COPY
); );
useEffect(() => { useEffect(() => {