コード例 #1
0
  def scenario_builder(self):
    """Returns an agent and environment pair."""
    env_params = lending_params.DelayedImpactParams(
        applicant_distribution=lending_params.two_group_credit_clusters(
            cluster_probabilities=self.cluster_probabilities,
            group_likelihoods=[self.group_0_prob, 1 - self.group_0_prob]),
        bank_starting_cash=self.bank_starting_cash,
        interest_rate=self.interest_rate,
        cluster_shift_increment=self.cluster_shift_increment,
    )
    env = lending.DelayedImpactEnv(env_params)

    agent_params = classifier_agents.ScoringAgentParams(
        feature_keys=['applicant_features'],
        group_key='group',
        default_action_fn=(lambda: 1),
        burnin=self.burnin,
        convert_one_hot_to_integer=True,
        threshold_policy=self.threshold_policy,
        skip_retraining_fn=lambda action, observation: action == 0,
        cost_matrix=params.CostMatrix(
            fn=0, fp=-1, tp=env_params.interest_rate, tn=0))

    agent = oracle_lending_agent.OracleThresholdAgent(
        action_space=env.action_space,
        reward_fn=rewards.BinarizedScalarDeltaReward(
            'bank_cash', baseline=env.initial_params.bank_starting_cash),
        observation_space=env.observation_space,
        params=agent_params,
        env=env)
    agent.seed(100)
    return env, agent
コード例 #2
0
  def test_oracle_maxutil_classifier_is_stable(self):
    env = lending.DelayedImpactEnv()

    agent_params = classifier_agents.ScoringAgentParams(
        feature_keys=['applicant_features'],
        group_key='group',
        default_action_fn=(lambda: 1),
        burnin=1,
        threshold_policy=threshold_policies.ThresholdPolicy.SINGLE_THRESHOLD,
        convert_one_hot_to_integer=True,
        cost_matrix=params.CostMatrix(
            fn=0, fp=-1, tp=env.initial_params.interest_rate, tn=0))

    agent = oracle_lending_agent.OracleThresholdAgent(
        action_space=env.action_space,
        observation_space=env.observation_space,
        reward_fn=rewards.BinarizedScalarDeltaReward('bank_cash'),
        params=agent_params,
        env=env)

    test_util.run_test_simulation(env=env, agent=agent)
    # Drop 0 threshold associated with burn-in.
    first_nonzero_threshold = None
    for thresh in agent.global_threshold_history:
      if thresh > 0:
        if first_nonzero_threshold is None:
          first_nonzero_threshold = thresh
        self.assertAlmostEqual(first_nonzero_threshold, thresh)
    # Make sure there is at least one non-zero threshold.
    self.assertIsNotNone(first_nonzero_threshold)
コード例 #3
0
 def test_final_credit_distribution_metric_can_interact_with_lending(self):
   env = lending.DelayedImpactEnv()
   env.set_scalar_reward(rewards.NullReward())
   # Use step=-1 to get the final credit distribution.
   final_distribution = lending_metrics.CreditDistribution(env, step=-1)
   initial_distribution = lending_metrics.CreditDistribution(env, step=0)
   test_util.run_test_simulation(
       env=env, metric=[final_distribution, initial_distribution])
コード例 #4
0
  def test_cumulative_count(self):
    env = lending.DelayedImpactEnv()
    metric = lending_metrics.CumulativeLoans(env)

    env.seed(100)
    _ = env.reset()
    for _ in range(10):
      env.step(np.asarray(1))

    result = metric.measure(env)
    self.assertEqual(result.shape, (2, 10))

    # On the first step, the combined number of loans given out should be 1.
    self.assertEqual(result[:, 0].sum(), 1)

    # On the last step, the combined number of loans given out should be 10.
    self.assertEqual(result[:, -1].sum(), 10)
コード例 #5
0
  def test_no_loans_to_group_zero(self):
    env = lending.DelayedImpactEnv()
    metric = lending_metrics.CumulativeLoans(env)

    env.seed(100)
    obs = env.reset()
    for _ in range(10):
      # action is 0 for group 0 and 1 for group 1.
      action = np.argmax(obs['group'])
      obs, _, _, _ = env.step(action)

    result = metric.measure(env)
    self.assertEqual(result.shape, (2, 10))

    # Group 0 gets no loans.
    self.assertEqual(result[0, -1], 0)

    # Group 1 gets at least 1 loan.
    self.assertGreater(result[1, -1], 0)
コード例 #6
0
    def test_higher_credit_scores_default_less(self):
        env = lending.DelayedImpactEnv()
        high_scores = []
        low_scores = []
        rng = np.random.RandomState()
        rng.seed(100)
        for _ in range(1000):
            applicant = env.initial_params.applicant_distribution.sample(rng)
            if np.argmax(applicant.features) > 4:
                high_scores.append(applicant)
            else:
                low_scores.append(applicant)

        self.assertNotEmpty(high_scores)
        self.assertNotEmpty(low_scores)

        self.assertLess(
            np.mean([applicant.will_default for applicant in high_scores]),
            np.mean([applicant.will_default for applicant in low_scores]))
コード例 #7
0
  def test_oracle_lending_agent_interacts(self):
    env = lending.DelayedImpactEnv()

    agent_params = classifier_agents.ScoringAgentParams(
        feature_keys=['applicant_features'],
        group_key='group',
        default_action_fn=(lambda: 1),
        burnin=1,
        convert_one_hot_to_integer=True,
        cost_matrix=params.CostMatrix(
            fn=0, fp=-1, tp=env.initial_params.interest_rate, tn=0))

    agent = oracle_lending_agent.OracleThresholdAgent(
        action_space=env.action_space,
        observation_space=env.observation_space,
        reward_fn=rewards.BinarizedScalarDeltaReward('bank_cash'),
        params=agent_params,
        env=env)

    test_util.run_test_simulation(env=env, agent=agent)
コード例 #8
0
  def test_measure_distribution_change_measurement(self):

    # The lower cluster has a 100% success rate and the upper cluster has a 0%
    # success rate. This causes applicants to move constantly between clusters.
    clusters = distributions.Mixture(
        components=[
            lending_params._credit_cluster_builder(
                group_membership=[1, 0],
                cluster_probs=[0.1, 0.9],
                success_probs=[1., 0.])(),
            lending_params._credit_cluster_builder(
                group_membership=[0, 1],
                cluster_probs=[0.8, 0.2],
                success_probs=[1., 0.])(),
        ],
        weights=(0.5, 0.5))

    env = lending.DelayedImpactEnv(
        lending_params.DelayedImpactParams(applicant_distribution=clusters))
    initial_distribution = lending_metrics.CreditDistribution(env, 0)
    final_distribution = lending_metrics.CreditDistribution(env, -1)

    # Giving a loan should change the distribution.
    env.step(np.asarray(1))
    # Take another step to move current state into history. This step does not
    # change the distribution because the loan is rejected.
    env.step(np.asarray(0))

    self.assertEqual({
        '0': [0.1, 0.9],
        '1': [0.8, 0.2]
    }, initial_distribution.measure(env))
    self.assertNotEqual({
        '0': [0.1, 0.9],
        '1': [0.8, 0.2]
    }, final_distribution.measure(env))
コード例 #9
0
    def test_credit_score_distributions_change(self):
        env = lending.DelayedImpactEnv()
        state = env._get_state()

        # Candidate is in group 0
        state.group = [1, 0]
        state.group_id = 0
        # Candidate will default.
        state.will_default = 1
        # Should move probability mass from clusters 3 to 2.
        state.applicant_features = [0] * 7
        state.applicant_features[3] = 1

        lending._CreditShift().update(state, lending.LoanDecision.ACCEPT)

        def get_cluster_probs(params):
            return params.applicant_distribution.components[0].weights

        self.assertLess(
            get_cluster_probs(state.params)[3],
            get_cluster_probs(env.initial_params)[3])
        self.assertGreater(
            get_cluster_probs(state.params)[2],
            get_cluster_probs(env.initial_params)[2])
コード例 #10
0
 def test_metric_can_interact_with_lending(self):
     env = lending.DelayedImpactEnv()
     metric = value_tracking_metrics.ValueChange(env, 'bank_cash')
     test_util.run_test_simulation(env=env, metric=metric)
コード例 #11
0
 def test_delayed_impact_env_has_multinomial_observation_space(self):
     env = lending.DelayedImpactEnv()
     for _ in range(10):
         features = env.observation_space.sample()['applicant_features']
         self.assertEqual(features.sum(), 1)
         self.assertSameElements(features, {0, 1})
コード例 #12
0
 def test_render_fails_for_high_dimensional_environments(self):
     env = lending.DelayedImpactEnv()
     test_util.run_test_simulation(env=env)
     with self.assertRaises(NotImplementedError):
         env.render()