Esempio n. 1
0
def add_person_level_characteristics(person, incarceration_event,
                                     characteristics):
    """Given |characteristics|, adds new characteristics that do not matter for aggregation and are only important for
    person-level metrics. These characteristics therefore are NOT used to generate the dictionaries with unique
    combinations, but are simply add-ons to those dictionaries.
    """

    characteristics_with_person_details = characteristics_with_person_id_fields(
        characteristics, incarceration_event.state_code, person,
        'incarceration')

    if isinstance(incarceration_event, IncarcerationStayEvent):
        if incarceration_event.most_serious_offense_statute:
            characteristics_with_person_details['most_serious_offense_ncic_code'] = \
                incarceration_event.most_serious_offense_ncic_code
        if incarceration_event.most_serious_offense_statute:
            characteristics_with_person_details['most_serious_offense_statute'] = \
                incarceration_event.most_serious_offense_statute
        if incarceration_event.admission_reason_raw_text:
            characteristics_with_person_details['admission_reason_raw_text'] = \
                incarceration_event.admission_reason_raw_text
    if isinstance(incarceration_event, IncarcerationAdmissionEvent):
        if incarceration_event.admission_reason_raw_text:
            characteristics_with_person_details['admission_reason_raw_text'] = \
                incarceration_event.admission_reason_raw_text
    return characteristics_with_person_details
Esempio n. 2
0
def characteristics_dict(person: StatePerson,
                         program_event: ProgramEvent) -> Dict[str, Any]:
    """Builds a dictionary that describes the characteristics of the person and event.

    Args:
        person: the StatePerson we are picking characteristics from
        program_event: the ProgramEvent we are picking characteristics from

    Returns:
        A dictionary populated with all relevant characteristics.
    """
    characteristics: Dict[str, Any] = {}

    event_date = program_event.event_date

    if isinstance(program_event, ProgramReferralEvent):
        if program_event.supervision_type:
            characteristics['supervision_type'] = program_event.supervision_type
        if program_event.assessment_score and program_event.assessment_type:
            assessment_bucket = assessment_score_bucket(
                assessment_score=program_event.assessment_score,
                assessment_level=None,
                assessment_type=program_event.assessment_type)

            if assessment_bucket and include_assessment_in_metric(
                    'program', program_event.state_code, program_event.assessment_type):
                characteristics['assessment_score_bucket'] = assessment_bucket
                characteristics['assessment_type'] = program_event.assessment_type

        if program_event.participation_status:
            characteristics['participation_status'] = program_event.participation_status
        if program_event.supervising_officer_external_id:
            characteristics['supervising_officer_external_id'] = program_event.supervising_officer_external_id
        if program_event.supervising_district_external_id:
            characteristics['supervising_district_external_id'] = program_event.supervising_district_external_id
    elif isinstance(program_event, ProgramParticipationEvent):
        characteristics['date_of_participation'] = event_date

        if program_event.supervision_type:
            characteristics['supervision_type'] = program_event.supervision_type
        if program_event.program_location_id:
            characteristics['program_location_id'] = program_event.program_location_id

    if program_event.program_id:
        characteristics['program_id'] = program_event.program_id

    characteristics = add_demographic_characteristics(characteristics, person, event_date)

    characteristics_with_person_details = characteristics_with_person_id_fields(
        characteristics, program_event.state_code, person, 'program')

    return characteristics_with_person_details
Esempio n. 3
0
def characteristics_dict(
        person: StatePerson, event: ReleaseEvent,
        metric_type: ReincarcerationRecidivismMetricType) -> Dict[str, Any]:
    """Builds a dictionary that describes the characteristics of the person and the release event.

    Release cohort, follow-up period, and methodology are not included in the output here. They are added into
    augmented versions of these combinations later.

    Args:
        person: the StatePerson we are picking characteristics from
        event: the ReleaseEvent we are picking characteristics from
        metric_type: The ReincarcerationRecidivismMetricType provided determines which fields should be added to the
            characteristics dictionary
    Returns:
        A dictionary populated with all relevant characteristics.
    """
    characteristics: Dict[str, Any] = {}

    if event.county_of_residence:
        characteristics['county_of_residence'] = event.county_of_residence

    if event.release_facility is not None:
        characteristics['release_facility'] = event.release_facility

    event_stay_length = stay_length_from_event(event)
    event_stay_length_bucket = stay_length_bucket(event_stay_length)
    characteristics['stay_length_bucket'] = event_stay_length_bucket

    characteristics = add_demographic_characteristics(
        characteristics, person, event.original_admission_date)

    if isinstance(
            event, RecidivismReleaseEvent
    ) and metric_type == ReincarcerationRecidivismMetricType.COUNT:
        time_at_liberty = days_at_liberty(event)

        characteristics['days_at_liberty'] = time_at_liberty

    characteristics = characteristics_with_person_id_fields(
        characteristics, event.state_code, person, 'recidivism')

    return characteristics
Esempio n. 4
0
def characteristics_dict(person: StatePerson,
                         supervision_time_bucket: SupervisionTimeBucket,
                         metric_type: SupervisionMetricType) -> Dict[str, Any]:
    """Builds a dictionary that describes the characteristics of the person and supervision_time_bucket.

    Args:
        person: the StatePerson we are picking characteristics from
        supervision_time_bucket: the SupervisionTimeBucket we are picking characteristics from
        metric_type: The SupervisionMetricType provided determines which fields should be added to the characteristics
            dictionary

    Returns:
        A dictionary populated with all relevant characteristics.
    """
    characteristics: Dict[str, Any] = {}

    include_revocation_dimensions = _include_revocation_dimensions_for_metric(
        metric_type)
    include_assessment_dimensions = _include_assessment_dimensions_for_metric(
        metric_type)
    include_demographic_dimensions = _include_demographic_dimensions_for_metric(
        metric_type)
    include_person_level_dimensions = _include_person_level_dimensions_for_metric(
        metric_type)

    if (metric_type == SupervisionMetricType.POPULATION
            and isinstance(supervision_time_bucket,
                           (RevocationReturnSupervisionTimeBucket,
                            NonRevocationReturnSupervisionTimeBucket))):
        if supervision_time_bucket.most_severe_violation_type:
            characteristics[
                'most_severe_violation_type'] = supervision_time_bucket.most_severe_violation_type
        if supervision_time_bucket.most_severe_violation_type_subtype:
            characteristics['most_severe_violation_type_subtype'] = \
                supervision_time_bucket.most_severe_violation_type_subtype
        if supervision_time_bucket.response_count is not None:
            characteristics[
                'response_count'] = supervision_time_bucket.response_count

    if include_revocation_dimensions and \
            isinstance(supervision_time_bucket,
                       RevocationReturnSupervisionTimeBucket):
        if supervision_time_bucket.revocation_type:
            characteristics[
                'revocation_type'] = supervision_time_bucket.revocation_type

        if supervision_time_bucket.source_violation_type:
            characteristics[
                'source_violation_type'] = supervision_time_bucket.source_violation_type

        if metric_type in [
                SupervisionMetricType.REVOCATION_ANALYSIS,
                SupervisionMetricType.REVOCATION_VIOLATION_TYPE_ANALYSIS
        ]:
            if supervision_time_bucket.most_severe_violation_type:
                characteristics[
                    'most_severe_violation_type'] = supervision_time_bucket.most_severe_violation_type

            if supervision_time_bucket.most_severe_violation_type_subtype:
                characteristics['most_severe_violation_type_subtype'] = \
                    supervision_time_bucket.most_severe_violation_type_subtype

            if metric_type in [SupervisionMetricType.REVOCATION_ANALYSIS]:
                if supervision_time_bucket.most_severe_response_decision:
                    characteristics['most_severe_response_decision'] = \
                        supervision_time_bucket.most_severe_response_decision

            if supervision_time_bucket.response_count is not None:
                characteristics[
                    'response_count'] = supervision_time_bucket.response_count

    if isinstance(supervision_time_bucket, SupervisionTerminationBucket):
        if supervision_time_bucket.termination_reason:
            characteristics[
                'termination_reason'] = supervision_time_bucket.termination_reason

    if supervision_time_bucket.supervision_type:
        characteristics[
            'supervision_type'] = supervision_time_bucket.supervision_type
    if supervision_time_bucket.case_type:
        characteristics['case_type'] = supervision_time_bucket.case_type

    if not include_revocation_dimensions and supervision_time_bucket.supervision_level:
        characteristics[
            'supervision_level'] = supervision_time_bucket.supervision_level

    if include_assessment_dimensions:
        # TODO(2853): Figure out more robust solution for not assessed people. Here we don't set assessment_type when
        #  someone is not assessed. This only works as desired because BQ doesn't rely on assessment_type at all.
        characteristics['assessment_score_bucket'] = 'NOT_ASSESSED'
        if supervision_time_bucket.assessment_score and supervision_time_bucket.assessment_type:
            assessment_bucket = assessment_score_bucket(
                supervision_time_bucket.assessment_score,
                supervision_time_bucket.assessment_level,
                supervision_time_bucket.assessment_type)

            if assessment_bucket and include_assessment_in_metric(
                    'supervision', supervision_time_bucket.state_code,
                    supervision_time_bucket.assessment_type):
                characteristics['assessment_score_bucket'] = assessment_bucket
                characteristics[
                    'assessment_type'] = supervision_time_bucket.assessment_type
    if supervision_time_bucket.supervising_officer_external_id:
        characteristics[
            'supervising_officer_external_id'] = supervision_time_bucket.supervising_officer_external_id

    if supervision_time_bucket.supervising_district_external_id:
        characteristics[
            'supervising_district_external_id'] = supervision_time_bucket.supervising_district_external_id

    if isinstance(supervision_time_bucket,
                  RevocationReturnSupervisionTimeBucket):
        event_date = supervision_time_bucket.revocation_admission_date
    elif isinstance(supervision_time_bucket, SupervisionTerminationBucket):
        event_date = supervision_time_bucket.termination_date
    else:
        year = supervision_time_bucket.year
        month = supervision_time_bucket.month

        event_date = date(year, month, 1)

    if include_demographic_dimensions:
        characteristics = add_demographic_characteristics(
            characteristics, person, event_date)

    if include_person_level_dimensions:
        characteristics = characteristics_with_person_id_fields(
            characteristics, person, 'supervision')

        if not include_revocation_dimensions and supervision_time_bucket.supervision_level_raw_text:
            characteristics['supervision_level_raw_text'] = \
                supervision_time_bucket.supervision_level_raw_text

        if metric_type == SupervisionMetricType.POPULATION:
            if isinstance(supervision_time_bucket,
                          (RevocationReturnSupervisionTimeBucket,
                           NonRevocationReturnSupervisionTimeBucket)):
                characteristics['is_on_supervision_last_day_of_month'] = \
                    supervision_time_bucket.is_on_supervision_last_day_of_month

        if metric_type == SupervisionMetricType.REVOCATION_ANALYSIS:
            if isinstance(supervision_time_bucket, RevocationReturnSupervisionTimeBucket) \
                    and supervision_time_bucket.violation_history_description:
                characteristics['violation_history_description'] = \
                    supervision_time_bucket.violation_history_description

        if include_revocation_dimensions and isinstance(
                supervision_time_bucket,
                RevocationReturnSupervisionTimeBucket):
            characteristics['revocation_admission_date'] = \
                supervision_time_bucket.revocation_admission_date

        if metric_type == SupervisionMetricType.ASSESSMENT_CHANGE:
            if isinstance(supervision_time_bucket, SupervisionTerminationBucket) \
                    and supervision_time_bucket.termination_date:
                characteristics[
                    'termination_date'] = supervision_time_bucket.termination_date

    return characteristics
Esempio n. 5
0
def characteristic_combinations(person: StatePerson,
                                supervision_time_bucket: SupervisionTimeBucket,
                                inclusions: Dict[str, bool],
                                metric_type: SupervisionMetricType) -> \
        List[Dict[str, Any]]:
    """Calculates all supervision metric combinations.

    Returns the list of all combinations of the metric characteristics, of all sizes, given the StatePerson and
    SupervisionTimeBucket. That is, this returns a list of dictionaries where each dictionary is a combination of 0
    to n unique elements of characteristics applicable to the given person and supervision_time_bucket.

    Args:
        person: the StatePerson we are picking characteristics from
        supervision_time_bucket: the SupervisionTimeBucket we are picking characteristics from
        inclusions: A dictionary containing the following keys that correspond
            to characteristic dimensions:
                - age_bucket
                - ethnicity
                - gender
                - race
            Where the values are boolean flags indicating whether to include
            the dimension in the calculations.
        metric_type: The SupervisionMetricType provided determines which fields should be added to the characteristics
            dictionary

    Returns:
        A list of dictionaries containing all unique combinations of
        characteristics.
    """
    characteristics: Dict[str, Any] = {}

    include_revocation_dimensions = _include_revocation_dimensions_for_metric(
        metric_type)
    include_assessment_dimensions = _include_assessment_dimensions_for_metric(
        metric_type)
    include_person_level_dimensions = _include_person_level_dimensions_for_metric(
        metric_type)

    if (metric_type == SupervisionMetricType.POPULATION
            and isinstance(supervision_time_bucket,
                           (RevocationReturnSupervisionTimeBucket,
                            NonRevocationReturnSupervisionTimeBucket))):
        if supervision_time_bucket.most_severe_violation_type:
            characteristics[
                'most_severe_violation_type'] = supervision_time_bucket.most_severe_violation_type
        if supervision_time_bucket.most_severe_violation_type_subtype:
            characteristics['most_severe_violation_type_subtype'] = \
                supervision_time_bucket.most_severe_violation_type_subtype
        if supervision_time_bucket.response_count is not None:
            characteristics[
                'response_count'] = supervision_time_bucket.response_count

    if include_revocation_dimensions and \
            isinstance(supervision_time_bucket,
                       RevocationReturnSupervisionTimeBucket):
        if supervision_time_bucket.revocation_type:
            characteristics[
                'revocation_type'] = supervision_time_bucket.revocation_type

        if supervision_time_bucket.source_violation_type:
            characteristics[
                'source_violation_type'] = supervision_time_bucket.source_violation_type

        if metric_type in [
                SupervisionMetricType.REVOCATION_ANALYSIS,
                SupervisionMetricType.REVOCATION_VIOLATION_TYPE_ANALYSIS
        ]:
            if supervision_time_bucket.most_severe_violation_type:
                characteristics[
                    'most_severe_violation_type'] = supervision_time_bucket.most_severe_violation_type

            if supervision_time_bucket.most_severe_violation_type_subtype:
                characteristics['most_severe_violation_type_subtype'] = \
                    supervision_time_bucket.most_severe_violation_type_subtype

            if metric_type in [SupervisionMetricType.REVOCATION_ANALYSIS]:
                if supervision_time_bucket.most_severe_response_decision:
                    characteristics['most_severe_response_decision'] = \
                        supervision_time_bucket.most_severe_response_decision

            if supervision_time_bucket.response_count is not None:
                characteristics[
                    'response_count'] = supervision_time_bucket.response_count

    if isinstance(supervision_time_bucket, SupervisionTerminationBucket):
        if supervision_time_bucket.termination_reason:
            characteristics[
                'termination_reason'] = supervision_time_bucket.termination_reason

    if supervision_time_bucket.supervision_type:
        characteristics[
            'supervision_type'] = supervision_time_bucket.supervision_type
    if supervision_time_bucket.case_type:
        characteristics['case_type'] = supervision_time_bucket.case_type

    if not include_revocation_dimensions and supervision_time_bucket.supervision_level:
        characteristics[
            'supervision_level'] = supervision_time_bucket.supervision_level

    if include_assessment_dimensions:
        # TODO(2853): Figure out more robust solution for not assessed people. Here we don't set assessment_type when
        #  someone is not assessed. This only works as desired because BQ doesn't rely on assessment_type at all.
        characteristics['assessment_score_bucket'] = 'NOT_ASSESSED'
        if supervision_time_bucket.assessment_score and supervision_time_bucket.assessment_type:
            assessment_bucket = assessment_score_bucket(
                supervision_time_bucket.assessment_score,
                supervision_time_bucket.assessment_level,
                supervision_time_bucket.assessment_type)

            if assessment_bucket and include_assessment_in_metric(
                    'supervision', supervision_time_bucket.state_code,
                    supervision_time_bucket.assessment_type):
                characteristics['assessment_score_bucket'] = assessment_bucket
                characteristics[
                    'assessment_type'] = supervision_time_bucket.assessment_type
    if supervision_time_bucket.supervising_officer_external_id:
        characteristics[
            'supervising_officer_external_id'] = supervision_time_bucket.supervising_officer_external_id

    if supervision_time_bucket.supervising_district_external_id:
        characteristics[
            'supervising_district_external_id'] = supervision_time_bucket.supervising_district_external_id
    if inclusions.get('age_bucket'):
        year = supervision_time_bucket.year
        month = supervision_time_bucket.month

        start_of_bucket = date(year, month, 1)
        entry_age = age_at_date(person, start_of_bucket)
        entry_age_bucket = age_bucket(entry_age)
        if entry_age_bucket is not None:
            characteristics['age_bucket'] = entry_age_bucket
    if inclusions.get('gender'):
        if person.gender is not None:
            characteristics['gender'] = person.gender

    if person.races or person.ethnicities:
        if inclusions.get('race'):
            races = person.races
        else:
            races = []

        if inclusions.get('ethnicity'):
            ethnicities = person.ethnicities
        else:
            ethnicities = []

        all_combinations = for_characteristics_races_ethnicities(
            races, ethnicities, characteristics)
    else:
        all_combinations = for_characteristics(characteristics)

    if include_person_level_dimensions:
        characteristics_with_person_details = characteristics_with_person_id_fields(
            characteristics, person, 'supervision')

        if not include_revocation_dimensions and supervision_time_bucket.supervision_level_raw_text:
            characteristics_with_person_details['supervision_level_raw_text'] = \
                supervision_time_bucket.supervision_level_raw_text

        if metric_type == SupervisionMetricType.POPULATION:
            if isinstance(supervision_time_bucket,
                          (RevocationReturnSupervisionTimeBucket,
                           NonRevocationReturnSupervisionTimeBucket)):
                characteristics_with_person_details['is_on_supervision_last_day_of_month'] = \
                    supervision_time_bucket.is_on_supervision_last_day_of_month

        if metric_type == SupervisionMetricType.REVOCATION_ANALYSIS:
            # Only include violation history descriptions on person-level metrics
            if isinstance(supervision_time_bucket, RevocationReturnSupervisionTimeBucket) \
                    and supervision_time_bucket.violation_history_description:
                characteristics_with_person_details['violation_history_description'] = \
                    supervision_time_bucket.violation_history_description

        all_combinations.append(characteristics_with_person_details)

    return all_combinations
Esempio n. 6
0
def characteristic_combinations(person: StatePerson,
                                event: ReleaseEvent,
                                inclusions: Dict[str, bool]) -> \
        List[Dict[str, Any]]:
    """Calculates all recidivism metric combinations.

    Returns the list of all combinations of the metric characteristics, of all sizes, given the StatePerson and
    ReleaseEvent. That is, this returns a list of dictionaries where each dictionary is a combination of 0 to n unique
    elements of characteristics, where n is the size of the given array.

    For each event, we need to calculate metrics across combinations of:
    Release Cohort; Follow-up Period (up to 10 years);
    MetricMethodologyType (Event-based, Person-based);
    Demographics (age, race, ethnicity, gender); Location (facility, region);
    Facility Stay Breakdown (stay length);
    Return Descriptors (return type, from supervision type)
    TODO: Add support for offense and sentencing type (Issues 33 and 32)

    Release cohort, follow-up period, and methodology are not included in the output here. They are added into
    augmented versions of these combinations later.

    The output for a black female age 24 and an incarceration that began in January 2008 and ended in February 2009 is
    equal to the output of:
            for_characteristics({'age': '<25', 'race': Race.BLACK,
                                 'gender': Gender.FEMALE,
                                 'stay_length_bucket': '12-24'})

    Our schema allows for a StatePerson to have more than one race. The output for a female age 24 who is both white
    and black and an incarceration that began in January 2008 and ended in February 2009 is equal to the union of the
    outputs for:

     for_characteristics({'age': '<25', 'race': Race.BLACK,
                                 'gender': Gender.FEMALE,
                                 'stay_length_bucket': '12-24'})

     and

     for_characteristics({'age': '<25', 'race': Race.WHITE,
                                 'gender': Gender.FEMALE,
                                 'stay_length_bucket': '12-24'})

    where there are no duplicate metrics in the output.

    Args:
        person: the StatePerson we are picking characteristics from
        event: the ReleaseEvent we are picking characteristics from
        inclusions: A dictionary containing the following keys that correspond to characteristic dimensions:
                - age_bucket
                - ethnicity
                - gender
                - race
                - release_facility
                - stay_length_bucket
            Where the values are boolean flags indicating whether to include the dimension in the calculations.

    Returns:
        A list of dictionaries containing all unique combinations of characteristics.
    """
    characteristics: Dict[str, Any] = {}

    if event.county_of_residence:
        characteristics['county_of_residence'] = event.county_of_residence

    if inclusions.get('age_bucket'):
        entry_age = age_at_date(person, event.original_admission_date)
        entry_age_bucket = age_bucket(entry_age)
        if entry_age_bucket is not None:
            characteristics['age_bucket'] = entry_age_bucket
    if inclusions.get('gender'):
        if person.gender is not None:
            characteristics['gender'] = person.gender
    if inclusions.get('release_facility'):
        if event.release_facility is not None:
            characteristics['release_facility'] = event.release_facility
    if inclusions.get('stay_length_bucket'):
        event_stay_length = stay_length_from_event(event)
        event_stay_length_bucket = stay_length_bucket(event_stay_length)
        characteristics['stay_length_bucket'] = event_stay_length_bucket
    if person.races or person.ethnicities:
        if inclusions.get('race'):
            races = person.races
        else:
            races = []

        if inclusions.get('ethnicity'):
            ethnicities = person.ethnicities
        else:
            ethnicities = []

        all_combinations = for_characteristics_races_ethnicities(
            races, ethnicities, characteristics)
    else:
        all_combinations = for_characteristics(characteristics)

    characteristics_with_person_details = characteristics_with_person_id_fields(
        characteristics, person, 'recidivism')

    all_combinations.append(characteristics_with_person_details)

    return all_combinations