# Calculating a Company's Probability of Default with Python

**Hugh Donnelly, CFA**

*AlphaWave Data*

**March 2021**

For this analysis, we use several Python-based scientific computing technologies along with the [AlphaWave Data Stock Analysis API](https://rapidapi.com/alphawave/api/stock-analysis/endpoints).  Jupyter Notebooks detailing this analysis are also available on [Google Colab](https://colab.research.google.com/drive/1GbxEJ1JuZUEviLCpRU7b73engWZzYYzh?usp=sharing) and [Github](https://github.com/AlphaWaveData/Jupyter-Notebooks/blob/master/AlphaWave%20Market-Implied%20Probability%20of%20Default%20Example.ipynb).

```python
import time
import requests
import selenium
import numpy as np
import pandas as pd
from sympy import *
from datetime import date
from datetime import timedelta
from selenium import webdriver
import pandas_datareader as dr
import matplotlib.pyplot as plt
from datetime import datetime as dt
from bs4 import BeautifulSoup as bs
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
```

We will use SM Energy (SM) in the subsequent code; however, this analysis works with the ticker of any large publicly traded company.

```python
# Required
company_ticker = 'SM'

# Optional
company_name = 'SM Energy'

# Optional Input Choices:
# ALL, Annual, Anytime, Bi-Monthly, Monthly, N/A, None, Pays At Maturity, Quarterly, Semi-Annual, Variable
coupon_frequency = 'Semi-Annual'
```

### Introduction to Probability of Default

The probability of default is the probability that a bond issuer will not meet its contractual obligations on schedule. Although the most common event of default is nonpayment leading to bankruptcy proceedings, the bond prospectus might identify other events of default, such as the failure to meet a different obligation or the violation of a financial covenant.

In the following example, we will determine the probability of default given corporate bond prices. The default probabilities that are reached in this exercise are called market-implied default probabilities. Historically, practitioners have focused on the one-year probability of default calculation. We know that over shorter horizons of one or two years firms are exposed to the credit cycle effect, while over longer horizons, the business cycle effect tends to have a lesser impact and the company’s capital structure becomes more important. This effect has made long-run risk levels less cyclical and more stable. Intuitively, default risk over a longer time period is less sensitive to the instantaneous default rates in the economy.  For this reason, we will focus on corporate bonds with one or two years until maturity to calculate the market-implied default probabilities.

We will verify the accuracy of the market-implied default probabilities with the Standard & Poor’s Average One-Year Transition Rates For Global Corporates using historical data from 1981-2019.  This transition matrix shows the observed historical probabilities of a particular rating transitioning to another rating, including default, over the course of one year.

In order to calculate the market-implied default probabilities, we must first acquire the company's current bond prices. Using a short Selenium script that emulates a user's keystrokes and clicks in a browser as a means of navigating to FINRA's TRACE bond data, we can access the data needed to calculate the market-implied default probabilities.

The following is an example script. In case you do not have [Selenium](https://pypi.org/project/selenium/) installed, you can visit their respective links and download them using pip in your terminal. We will also need a chromedriver (the simulated chrome browser Selenium controls) and to download it using Python you can use the [webdriver-manager](https://pypi.org/project/webdriver-manager/) package also found in PyPi.

You will need to insert your own path to your chromedriver in the code block below.

```python
# Selenium script
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
driver = webdriver.Chrome(options=chrome_options, executable_path=r'/PATH/TO/YOUR/chromedriver')

# store starting time
begin = time.time()

# FINRA's TRACE Bond Center
driver.get('http://finra-markets.morningstar.com/BondCenter/Results.jsp')

# click agree
WebDriverWait(driver, 10).until(EC.element_to_be_clickable(
    (By.CSS_SELECTOR, ".button_blue.agree"))).click()

# click edit search
WebDriverWait(driver, 10).until(EC.element_to_be_clickable(
    (By.CSS_SELECTOR, 'a.qs-ui-btn.blue'))).click()

# input Issuer Name
WebDriverWait(driver, 10).until(EC.presence_of_element_located(
    (By.CSS_SELECTOR, 'input[id=firscreener-issuer]')))
inputElement = driver.find_element_by_id("firscreener-issuer")
inputElement.send_keys(company_name)

# input Symbol
WebDriverWait(driver, 10).until(EC.presence_of_element_located(
    (By.CSS_SELECTOR, 'input[id=firscreener-cusip]')))
inputElement = driver.find_element_by_id("firscreener-cusip")
inputElement.send_keys(company_ticker)

# click advanced search
WebDriverWait(driver, 10).until(EC.element_to_be_clickable(
    (By.CSS_SELECTOR, 'a.ms-display-switcher.hide'))).click()

# input Coupon Frequency
WebDriverWait(driver, 10).until(EC.presence_of_element_located(
    (By.CSS_SELECTOR, 'select[name=interestFrequency]')))
Select((driver.find_elements_by_css_selector(
    'select[name=interestFrequency]'))[0]).select_by_visible_text(coupon_frequency)

# click show results
WebDriverWait(driver, 10).until(EC.element_to_be_clickable(
    (By.CSS_SELECTOR, 'input.button_blue[type=submit]'))).click()

# wait for results
WebDriverWait(driver, 10).until(EC.presence_of_element_located(
    (By.CSS_SELECTOR, '.rtq-grid-row.rtq-grid-rzrow .rtq-grid-cell-ctn')))

# create dataframe from scrape
frames = []
for page in range(1, 11):
    bonds = []
    WebDriverWait(driver, 10).until(EC.presence_of_element_located(
        (By.CSS_SELECTOR, (f"a.qs-pageutil-btn[value='{str(page)}']"))))  # wait for page marker to be on expected page
    time.sleep(2)

    headers = [title.text for title in driver.find_elements_by_css_selector(
    '.rtq-grid-row.rtq-grid-rzrow .rtq-grid-cell-ctn')[1:]]

    tablerows = driver.find_elements_by_css_selector(
        'div.rtq-grid-bd > div.rtq-grid-row')
    for tablerow in tablerows:
        tablerowdata = tablerow.find_elements_by_css_selector(
            'div.rtq-grid-cell')
        bond = [item.text for item in tablerowdata[1:]]
        bonds.append(bond)

        # Convert to Dataframe
        df = pd.DataFrame(bonds, columns=headers)

    frames.append(df)

    try:
        driver.find_element_by_css_selector('a.qs-pageutil-next').click()
    except:
        break

bond_prices_df = pd.concat(frames)

# store end time
end = time.time()

# total time taken
print(f"Total runtime of the program is {end - begin} seconds")

bond_prices_df
```

    Total runtime of the program is 6.986101150512695 seconds

      Issuer Name
      Symbol
      Callable
      Sub-Product Type
      Coupon
      Maturity
      Moody's®
      S&P
      Price
      Yield

      0
      SM ENERGY CO
      SM4141342
      Yes
      Corporate Bond
      5.000
      01/15/2024
      Caa2
      B-
      97.100
      6.116

      1
      SM ENERGY CO
      SM4243713
      Yes
      Corporate Bond
      5.625
      06/01/2025
      Caa2
      B-
      95.250
      6.933

      2
      SM ENERGY CO
      SM4269795
      Yes
      Corporate Bond
      6.125
      11/15/2022
      Caa2
      B-
      100.025
      6.102

      3
      SM ENERGY CO
      SM4392432

      Corporate Bond
      1.500
      07/01/2021

      98.400
      5.667

      4
      SM ENERGY CO
      SM4401573
      Yes
      Corporate Bond
      6.750
      09/15/2026
      Caa2
      B-
      95.500
      7.765

      5
      SM ENERGY CO
      SM4664064
      Yes
      Corporate Bond
      6.625
      01/15/2027
      Caa2
      B-
      95.020
      7.694

      6
      SM ENERGY CO
      SM5003694
      Yes
      Corporate Bond
      10.000
      01/15/2025
      B3
      B
      113.269
      4.941

We will now filter the corporate bond prices dataframe to align with the purpose of this example using the code below.

```python
def bond_dataframe_filter(df):
# Drop bonds with missing yields and missing credit ratings
    df['Yield'].replace('', np.nan, inplace=True)
    df["Moody's®"].replace({'WR':np.nan,'':np.nan}, inplace=True)
    df["S&P"].replace({'NR':np.nan,'':np.nan}, inplace=True)
    df = df.dropna(subset=['Yield'])
    df = df.dropna(subset=["Moody's®"])
    df = df.dropna(subset=["S&P"])

# Create Maturity Years column that aligns with Semi-Annual Payments from corporate bonds
    df['Yield'] = df['Yield'].astype(float)
    df['Coupon'] = df['Coupon'].astype(float)
    df['Price'] = df['Price'].astype(float)
    now = dt.strptime(date.today().strftime('%m/%d/%Y'), '%m/%d/%Y')
    df['Maturity'] = pd.to_datetime(df['Maturity']).dt.strftime('%m/%d/%Y')
    daystillmaturity = []
    yearstillmaturity = []
    for maturity in df['Maturity']:
        daystillmaturity.append(
            (dt.strptime(maturity, '%m/%d/%Y') - now).days)
        yearstillmaturity.append(
            (dt.strptime(maturity, '%m/%d/%Y') - now).days/360)
    df = df.reset_index(drop=True)
    df['Maturity'] = pd.Series(daystillmaturity)
#         df['Maturity Years'] = pd.Series(yearstillmaturity).round() # Better for Annual Payments
    df['Maturity Years'] = round(pd.Series(yearstillmaturity)/0.5)*0.5 # Better for Semi-Annual Payments

# Target bonds with short-term maturities
    df['Maturity'] = df['Maturity'].astype(float)
    df = df.loc[df['Maturity'] >= 0]
    years_mask = (df['Maturity Years'] > 0) & (df['Maturity Years'] <= 2)
    df = df.loc[years_mask]
    return df
```

```python
bond_df_result = bond_dataframe_filter(bond_prices_df)
bond_df_result
```

      Issuer Name
      Symbol
      Callable
      Sub-Product Type
      Coupon
      Maturity
      Moody's®
      S&P
      Price
      Yield
      Maturity Years

      2
      SM ENERGY CO
      SM4269795
      Yes
      Corporate Bond
      6.125
      622.0
      Caa2
      B-
      100.025
      6.102
      1.5

### 1. Market-Implied Probability of Default

To calculate the probability of default using current corporate bond prices, we will use bond valuation techniques. The valuation of corporate bonds is similar to that of any risky asset; it is dependent on the present value of future expected cash flows, discounted at a risk-adjusted rate (similar to Discounted Cash Flow analysis).

\begin{equation*}
BOND\ PRICE = \frac{ECF_1}{1+d}\ +\ \frac{ECF_2}{(1+d)^2}\ +\ \frac{ECF_3}{(1+d)^3}
\end{equation*}

$ECF = Expected\ Cash\ Flow$

$d = Risk-adjusted\ Discount\ Rate$

Corporate bond valuation also accounts for the probability of the bond defaulting and not paying back the principal in full.

**1a. Estimating the Expected Cash Flows**

The first step in valuing the bond is to find the Expected Cash Flow at each period. This is done by adding the product of the Default Payout and the Probability of Default (P) with the product of the promised payment (Coupon Payments and repayment of Principal) and the probability of not defaulting (1-P), which is also referred to as the probability of survival.

$ECF_1 = (P)*(Default\ Payout)\ +\ (1-P)*(Coupon\ Payment)$

$ECF_2 = (1-P)*\{(P)\ *(Default\ Payout)\ +\ (1-P)*(Coupon\ Payment)\}$

$ECF_3 = (1-P)^2*\{(P)\ *(Default\ Payout)\ +\ (1-P)*(Coupon\ Payment\ +\ Principal)\}$

$P = Probability\ of\ Default$

$Default\ Payout = Principal\ *\ Recovery\ Rate$

The Default Payout is calculated as the product of the Recovery Rate and the Principal if the bond defaults. In the following example, the Principal will be at par value for the bond (e.g. $100). The Recovery Rate is the percentage of the loss recovered from a bond in default. The Recovery Rate varies by industry, the degree of seniority in the capital structure, the amount of leverage in the capital structure in total, and whether a particular security is secured or otherwise collateralized. We assume a 40% Recovery Rate for the corporate bonds in the following example, which is a common baseline assumption in practice.

The code in the below function shows how the Expected Cash Flow is calculated at each period.  We then use the solve function from the Python library *sympy* to calculate the Probability of Default that will equate future Expected Cash Flows with the current price of the corporate bond when discounted at the risk-adjusted rate.  Running the cell below defines the function for use, but it will not run the function.  We will wait to run the function until after the Risk-adjusted Discount Rate is calculated.

```python
def bonds_probability_of_default(coupon, maturity_years, bond_price, principal_payment, risk_adjusted_discount_rate):

    price = bond_price
    prob_default_exp = 0

#     times = np.arange(1, maturity_years+1) # For Annual Cashflows
#     annual_coupon = coupon # For Annual Cashflows
    times = np.arange(0.5, (maturity_years-0.5)+1,0.5) # For Semi-Annual Cashflows
    semi_annual_coupon = coupon/2 # For Semi-Annual Cashflows

    # Calculation of Expected Cash Flow
    cashflows = np.array([])
    for i in times[:-1]:
#         cashflows = np.append(cashflows, annual_coupon) # For Annual Cashflows
#     cashflows = np.append(cashflows, annual_coupon+principal_payment)#  For Annual Cashflows
        cashflows = np.append(cashflows, semi_annual_coupon) # For Semi-Annual Cashflows
    cashflows = np.append(cashflows, semi_annual_coupon+principal_payment) # For Semi-Annual Cashflows

    for i in range(len(times)):
#         This code block is used if there is only one payment remaining
        if len(times) == 1:
            prob_default_exp += ((cashflows[i]*(1-P) + cashflows[i]*recovery_rate*P) / \
                                np.power((1 + risk_adjusted_discount_rate), times[i]))
#         This code block is used if there are multiple payments remaining
        else:
#             For Annual Cashflows
#             if times[i] == 1:
#                 prob_default_exp += ((cashflows[i]*(1-P) + principal_payment*recovery_rate*P) / \
#                                     np.power((1 + risk_adjusted_discount_rate), times[i]))
#             For Semi-Annual Cashflows
            if times[i] == 0.5:
                prob_default_exp += ((cashflows[i]*(1-P) + principal_payment*recovery_rate*P) / \
                                    np.power((1 + risk_adjusted_discount_rate), times[i]))
#             Used for either Annual or Semi-Annual Cashflows
            else:
                prob_default_exp += (np.power((1-P), times[i-1])*(cashflows[i]*(1-P) + principal_payment*recovery_rate*P)) / \
                                    np.power((1 + risk_adjusted_discount_rate), times[i])

    prob_default_exp = prob_default_exp - price
    implied_prob_default = solve(prob_default_exp, P)
    implied_prob_default = round(float(implied_prob_default[0]) * 100, 2)

    if implied_prob_default < 0:
        return 0.0
    else:
        return implied_prob_default
```

**1b. Estimating the Risk-Adjusted Discount Rate**

After the Expected Cash Flows are calculated, they are discounted back to period 0 at a Risk-adjusted Discount Rate (d) to calculate the bond’s price. A Risk-adjusted Discount Rate is the rate obtained by combining an Expected Risk Premium with the Risk-free Rate during the calculation of the present value of a risky investment.

\begin{equation*}
Risk-adjusted\ Discount\ Rate\ =\ Risk-free\ Interest\ Rate\ +\ Expected\ Risk\ Premium
\end{equation*}

We use the Risk-adjusted Discount Rate in order to account for the liquidity, maturity, and tax considerations that cause corporate bonds to have an observed spread over the yield on a risk-free bond like government bonds. The minimum required return expected for a bond investor is equal to the sum of the following, which accounts for this spread between corporate bonds and risk-free bonds:

* **Default Risk Premium** – Compensates investors for the business’ likelihood of default.
* **Liquidity Premium** – Compensates investors for investing in less liquid securities such as bonds. Government bonds typically are more liquid than corporate bonds. Government bonds are available in greater supply than even the most liquid corporates and have demand from a wider set of institutional investors. In addition, government bonds can be used more readily as collateral in repo transactions and for centrally cleared derivatives.
* **Maturity Premium** – Compensates investors for the risk associated with bonds that mature many years into the future, which inherently carry more risk.
* **Taxation Premium** – Compensates investors for the taxable income that bonds generate. Interest income on US corporate bonds is taxable by both the federal and state governments. Government debt, however, is exempt from taxes at the state level.
* **Projected Inflation** – Accounts for the devaluation of currency over time.
* **Risk-free Rate** – Refers to the rate of return an investor can expect on a riskless security (such as a T-bill).

We begin our calculation of the Risk-adjusted Discount Rate by first turning our attention to estimating the Expected Risk Premium.

*Estimating the Expected Risk Premium*

The Expected Risk Premium is obtained by subtracting the Risk-free Rate of Return from the Market Rate of Return and then multiplying the result by the Beta that adjusts based on the magnitude of the investment risk involved. By carefully selecting a proxy short-term corporate bond's Beta to the overall market, we can calculate an Expected Risk Premium that will result in a Risk-adjusted Discount Rate that incorporates liquidity, maturity, and tax considerations to produce a more accurate Probability of Default when using the bond valuation technique.

\begin{equation*}
Expected\ Risk\ Premium\ =\ (Market\ Rate\ of\ Return\ \ \ -\ \ \ Risk-free\ Rate\ of\ Return)\ *\ Beta
\end{equation*}

To calculate the Expected Risk Premium, we must first calculate the Market Rate of Return.  We can use the Capital Asset Pricing Model (CAPM) to determine the Market Rate of Return.

$$r_m = r_f\ +(\beta*MRP)$$

$r_m = Market\ Rate\ of\ Return$

$r_f = Risk-free\ Rate$

$\beta = Beta$

$MRP = Market\ Risk\ Premium$

CAPM is an equilibrium model that takes the Risk-free Rate, the stock market's Beta, and the Market Risk Premium as inputs.  Let's now determine the value for each of these inputs.

Government securities are assumed to be risk-free, at least from a credit standpoint.  With this assumption, the appropriate rate to use in the Market Rate of Return calculation is the government security having approximately the same duration as the asset being valued and sufficient liquidity so that the yield does not have an embedded liquidity risk premium.  Equities are assumed to have a long duration, so a long-term government bond yield is an appropriate proxy for the Risk-free Rate.

In this step, the yield on the 10 Year U.S. Treasury Note will be used as the Risk-free Rate.  We can scrape the current yield on the 10 Year U.S. Treasury Note from Yahoo Finance using the code below.

```python
# Ten-Year Risk-free Rate
timespan = 100
current_date = date.today()
past_date = current_date-timedelta(days=timespan)
ten_year_risk_free_rate_df = dr.DataReader('^TNX', 'yahoo', past_date, current_date)
ten_year_risk_free_rate = (ten_year_risk_free_rate_df.iloc[len(ten_year_risk_free_rate_df)-1,5])/100
ten_year_risk_free_rate
```

    0.014859999418258668

The Market Risk Premium should be the expected return on the market index less the expected return (or yield) on the long-term government bond.  For our purposes, we use the annual [Market Risk Premium](http://pages.stern.nyu.edu/~adamodar/New_Home_Page/datafile/ctryprem.html) provided by Aswath Damodaran, who is a professor at the Stern School of Business at New York University.  Professor Damodaran teaches Corporate Finance and Equity Instruments & Markets.  He provides a multitude of financial information and I encourage you to visit his [website](http://pages.stern.nyu.edu/~adamodar/).

```python
# Market Risk Premium
market_risk_premium = 0.0472
```

According to asset pricing theory, Beta represents the type of risk, systematic risk, that cannot be diversified away. By definition, the market itself has a Beta of 1.  As a result, Beta will be equal to 1 when calculating the Market Rate of Return.

```python
# Market Equity Beta
stock_market_beta = 1
```

We now have all the inputs required to calculate the Market Rate of Return.

```python
# Market Rate of Return
market_rate_of_return = ten_year_risk_free_rate + (stock_market_beta*market_risk_premium)
market_rate_of_return
```

    0.06205999941825867

Now that we have calculated the Market Rate of Return, we can determine the Expected Risk Premium by subtracting the Risk-free Rate from the Market Rate of Return and multiplying the result by the Beta for the bond.

\begin{equation*}
Expected\ Risk\ Premium\ =\ (Market\ Rate\ of\ Return\ \ \ -\ \ \ Risk-free\ Rate\ of\ Return)\ *\ Beta
\end{equation*}

In this step, we will use a one-year Risk-free Rate so that the Expected Risk Premium matches the duration we want for the Risk-adjusted Discount Rate.  We accomplish this by taking the yield on the very liquid 10 Year U.S. Treasury Note and raising it to the power of 1/10 in order to convert the yield to a one-year equivalent.

```python
# One-Year Risk-free Rate
one_year_risk_free_rate = (1 + ten_year_risk_free_rate)**(1/10) - 1
one_year_risk_free_rate
```

    0.0014761555839097884

The final component needed to calculate the Expected Risk Premium is the corporate bond's Beta.  Knowing that differences in liquidity within the universe of corporate bonds are great, we use the Vanguard Short-Term Corporate Bond Index Fund ETF Shares (VCSH) as a proxy for short-term maturity bonds.  The Beta from this Short-Term Corporate Bond Index will enable us to embed some of the liquidity and maturity risk into the Risk-adjusted Discount Rate that will be used to calculate the Probability of Default for the corporate bonds we will be analyzing.  This should allow for better isolation of the credit risk associated with the chosen bonds.

A bond's Beta is the sensitivity of that bond's return to the return of the market index.  It is a measure of systematic risk and can be obtained using the [Key Statistics](https://rapidapi.com/alphawave/api/stock-analysis?endpoint=apiendpoint_dff4b882-4be4-4169-a700-04275c92bdce) endpoint from the [AlphaWave Data Stock Analysis API](https://rapidapi.com/alphawave/api/stock-analysis/endpoints) using the code below. You will need to insert your own x-rapidapi-host and x-rapidapi-key information in the code blocks below.

```python
# Vanguard Short-Term Corporate Bond Index Fund ETF Shares
bond_fund_ticker = 'VCSH'
```

```python
url = "https://stock-analysis.p.rapidapi.com/api/v1/resources/key-stats"

querystring = {"ticker":bond_fund_ticker}

headers = {
    'x-rapidapi-host': "YOUR_X-RAPIDAPI-HOST_WILL_COPY_DIRECTLY_FROM_RAPIDAPI_PYTHON_CODE_SNIPPETS",
    'x-rapidapi-key': "YOUR_X-RAPIDAPI-KEY_WILL_COPY_DIRECTLY_FROM_RAPIDAPI_PYTHON_CODE_SNIPPETS"
    }

bond_fund_key_stats_response = requests.request("GET", url, headers=headers, params=querystring)

# Create Key Statistics DataFrame
bond_fund_key_stats_df = pd.DataFrame.from_dict(bond_fund_key_stats_response.json())
bond_fund_key_stats_df = bond_fund_key_stats_df.transpose()
bond_fund_key_stats_df
```

      Value

      52-week range
      71.19 - 83.50

      Ask
      82.65 x 1800

      Avg. volume
      3430085

      Beta (5Y monthly)
      0.58

      Bid
      82.64 x 900

      Day's range
      82.60 - 82.68

      Expense ratio (net)
      0.05%

      Inception date
      2009-11-19

      NAV
      82.65

      Net assets
      44.06B

      Open
      82.63

      PE ratio (TTM)
      0

      Previous close
      82.74

      Volume
      928994

      YTD daily total return
      -0.21%

      Yield
      2.27%

```python
# Bond's Beta
bond_beta = float(bond_fund_key_stats_df.loc[r'Beta (5Y monthly)'])
bond_beta
```

    0.58

We now have all the components required to calculate the Expected Risk Premium.

```python
# Expected Risk Premium
expected_risk_premium = (market_rate_of_return - one_year_risk_free_rate) * bond_beta
expected_risk_premium
```

    0.035138629423922346

With the Expected Risk Premium now in hand, we revisit the Risk-adjusted Discount Rate equation:

\begin{equation*}
Risk-adjusted\ Discount\ Rate\ =\ Risk-free\ Interest\ Rate\ +\ Expected\ Risk\ Premium
\end{equation*}

The final input required for the Risk-adjusted Discount Rate is the Risk-free Interest Rate, which we define next.

*Estimating the Risk-Free Rate*

We will again use a one-year Risk-free Rate so that it matches the duration we want for the Risk-adjusted Discount Rate, which we will use to discount Expected Cash Flows to determine the Probability of Default.

```python
# One-Year Risk-free Rate
one_year_risk_free_rate = (1 + ten_year_risk_free_rate)**(1/10) - 1
one_year_risk_free_rate
```

    0.0014761555839097884

We can now combine the Risk-free Interest Rate and the Expected Risk Premium to obtain the Risk-adjusted Discount Rate.

```python
# Risk-adjusted Discount Rate
risk_adjusted_discount_rate = one_year_risk_free_rate + expected_risk_premium
risk_adjusted_discount_rate
```

    0.036614785007832135

**1c. Estimating the Market-Implied Probability of Default**

Given the semi-annual coupon payment frequency for the bonds we are analyzing, we can feed the above annual Risk-adjusted Discount Rate into the *bonds_probability_of_default* function defined earlier because there is code in this function that will convert these annual rates into semi-annual rates.

Our last step before running the *bonds_probability_of_default* function is to define the Principal payment, the Recovery Rate, and the symbol for Probability of Default (P) that the solve function from the Python library *sympy* will use to calculate the Probability of Default by equating future Expected Cash Flows with the current price of the corporate bond when discounted at the Risk-adjusted Rate.

```python
# Variables defined for bonds_probability_of_default function
principal_payment = 100
recovery_rate = .40
P = symbols('P')
```

We are now ready to run the *bonds_probability_of_default* function to calculate the market-implied probability of default for the chosen corporate bonds.

```python
# This calculation may take some time if there are many coupon payments
bond_df_result['Probability of Default %'] = bond_df_result.apply(lambda row : bonds_probability_of_default(row['Coupon'], row['Maturity Years'], \
                                                    row['Price'], principal_payment, risk_adjusted_discount_rate), axis = 1)

bond_df_result
```

      Issuer Name
      Symbol
      Callable
      Sub-Product Type
      Coupon
      Maturity
      Moody's®
      S&P
      Price
      Yield
      Maturity Years
      Probability of Default %

      2
      SM ENERGY CO
      SM4269795
      Yes
      Corporate Bond
      6.125
      622.0
      Caa2
      B-
      100.025
      6.102
      1.5
      4.21

The below code will plot the market-implied probability of default and the Standard & Poor’s credit rating at each bond's maturity.  The next section will discuss credit ratings from rating agencies in more detail and how they can be used to verify the market-implied probability of default.

```python
def prob_default_term_structure(df):

        fig, (ax1, ax2) = plt.subplots(1, 2, clear=True)
        fig.subplots_adjust(wspace=.5)
        Mgroups = df.groupby("Moody's®")
        ax1.clear()
        ax1.margins(0.5)
        ax1.set_xlabel('Days Until Maturity')
        ax1.set_ylabel('Probability of Default %')
        ax1.set_title("Moody's® Ratings")
        for name, group in Mgroups:
            ax1.plot(group['Maturity'], group['Probability of Default %'],
                     marker='o', linestyle='', ms=12, label=name)
        ax1.legend(numpoints=1, loc='upper left')

        SPgroups = df.groupby("S&P")
        ax2.clear()
        ax2.margins(0.5)
        ax2.set_xlabel('Days Until Maturity')
        ax2.set_ylabel('Probability of Default %')
        ax2.set_title("S&P Ratings")

        for name, group in SPgroups:
            ax2.plot(group['Maturity'], group['Probability of Default %'],
                     marker='o', linestyle='', ms=12, label=name)
        ax2.legend(numpoints=1, loc='upper left')
        plt
```

```python
prob_default_term_structure(bond_df_result)
```

### 2. Probability of Default using Transition Matrices

Credit ratings are used in the wholesale market for bonds issued by corporations and government entities as well as for asset-backed securities (ABS). The three major global credit rating agencies are Moody’s Investors Service, Standard & Poor’s, and Fitch Ratings. Each provides quality ratings for issuers as well as specific issues. These are ordinal ratings focusing on the probability of default.

The credit rating agencies consider the expected loss given default by means of notching, which is an adjustment to the issuer rating to reflect the priority of claim for specific debt issues of that issuer and to reflect any subordination. The issuer rating is typically for senior unsecured debt. The rating on subordinated debt is then adjusted, or “notched,” by lowering it one or two levels—for instance, from A+ down to A or further down to A–. This inclusion of loss given default in addition to the probability of default explains why they are called “credit ratings” and not just “default ratings.”

The rating agencies report transition matrices based on their historical data. We can verify the accuracy of the market-implied default probabilities with these rating agencies' transition matrices. Using the code below, we can obtain the Standard & Poor’s Average One-Year Transition Rates For Global Corporates using historical data from 1981-2019 to verify the market-implied default probabilities calculated earlier.

```python
tgt_website = r'https://www.spglobal.com/ratings/en/research/articles/200429-default-transition-and-recovery-2019-annual-global-corporate-default-and-rating-transition-study-11444862'
```

```python
def get_transition_matrix(tgt_website):

    df_list = pd.read_html(tgt_website)
    matrix_result_df = df_list[22]

    return matrix_result_df

transition_matrix_df = get_transition_matrix(tgt_website)
```

```python
sp_clean_result_df = pd.DataFrame(transition_matrix_df.iloc[:34,:19].dropna(axis=0))
sp_clean_result_df
```

      Average One-Year Transition Rates For Global Corporates By Rating Modifier (1981-2019) (%)

      From/to
      AAA
      AA+
      AA
      AA-
      A+
      A
      A-
      BBB+
      BBB
      BBB-
      BB+
      BB
      BB-
      B+
      B
      B-
      CCC
      D

      0
      AAA
      87.03
      5.89
      2.51
      0.69
      0.16
      0.24
      0.13
      0.00
      0.05
      0.00
      0.03
      0.05
      0.03
      0.00
      0.03
      0.00
      0.05
      0.00

      2
      AA+
      2.31
      78.94
      10.91
      3.54
      0.71
      0.33
      0.19
      0.05
      0.09
      0.05
      0.00
      0.00
      0.00
      0.00
      0.00
      0.00
      0.00
      0.00

      4
      AA
      0.42
      1.31
      80.76
      8.53
      2.72
      1.15
      0.36
      0.39
      0.13
      0.08
      0.05
      0.03
      0.02
      0.02
      0.00
      0.02
      0.05
      0.02

      6
      AA-
      0.04
      0.11
      3.77
      78.80
      9.68
      2.19
      0.60
      0.25
      0.15
      0.07
      0.03
      0.00
      0.00
      0.03
      0.08
      0.00
      0.00
      0.03

      8
      A+
      0.00
      0.06
      0.44
      4.44
      78.38
      8.73
      2.15
      0.61
      0.34
      0.09
      0.06
      0.09
      0.01
      0.07
      0.03
      0.00
      0.00
      0.05

      10
      A
      0.03
      0.04
      0.22
      0.41
      5.32
      78.88
      6.74
      2.38
      0.86
      0.27
      0.10
      0.10
      0.06
      0.08
      0.02
      0.00
      0.01
      0.05

      12
      A-
      0.04
      0.01
      0.06
      0.15
      0.42
      6.49
      78.12
      7.23
      1.98
      0.57
      0.13
      0.13
      0.11
      0.10
      0.02
      0.01
      0.03
      0.06

      14
      BBB+
      0.00
      0.01
      0.05
      0.06
      0.20
      0.74
      7.13
      75.83
      7.98
      1.56
      0.36
      0.29
      0.13
      0.15
      0.10
      0.02
      0.06
      0.10

      16
      BBB
      0.01
      0.01
      0.04
      0.03
      0.10
      0.31
      1.00
      7.73
      76.00
      6.11
      1.34
      0.58
      0.27
      0.22
      0.11
      0.03
      0.05
      0.16

      18
      BBB-
      0.01
      0.01
      0.02
      0.04
      0.06
      0.14
      0.25
      1.17
      9.31
      72.40
      5.47
      2.08
      0.83
      0.36
      0.22
      0.16
      0.21
      0.25

      20
      BB+
      0.04
      0.00
      0.00
      0.03
      0.03
      0.08
      0.08
      0.41
      1.59
      11.33
      65.29
      7.42
      2.61
      0.95
      0.53
      0.24
      0.36
      0.31

      22
      BB
      0.00
      0.00
      0.03
      0.01
      0.00
      0.06
      0.05
      0.16
      0.47
      2.00
      9.44
      65.41
      8.46
      2.22
      1.02
      0.31
      0.52
      0.51

      24
      BB-
      0.00
      0.00
      0.00
      0.01
      0.01
      0.01
      0.05
      0.09
      0.23
      0.35
      1.69
      9.57
      63.71
      8.42
      3.04
      0.81
      0.66
      0.91

      26
      B+
      0.00
      0.01
      0.00
      0.03
      0.00
      0.03
      0.06
      0.04
      0.05
      0.10
      0.31
      1.42
      8.17
      62.91
      9.20
      2.51
      1.71
      1.98

      28
      B
      0.00
      0.00
      0.01
      0.01
      0.00
      0.03
      0.04
      0.02
      0.05
      0.03
      0.11
      0.23
      1.09
      7.38
      62.00
      9.32
      3.85
      3.20

      30
      B-
      0.00
      0.00
      0.00
      0.00
      0.02
      0.03
      0.00
      0.06
      0.05
      0.10
      0.08
      0.13
      0.46
      2.18
      10.06
      54.63
      11.70
      6.49

      32
      CCC/C
      0.00
      0.00
      0.00
      0.00
      0.03
      0.00
      0.08
      0.05
      0.08
      0.05
      0.03
      0.16
      0.40
      0.98
      2.57
      9.41
      43.64
      27.08

The above is the Standard & Poor’s 2019 transition matrix. It shows the probabilities of a particular rating transitioning to another over the course of the following year. An A-rated issuer has an 78.88% probability of remaining at that level, a 0.03% probability of moving up to AAA; a 0.22% probability of moving up to AA; an 0.86% probability of moving down to BBB; 0.10% down to BB; 0.02% to B, 0.01% to CCC, CC, or C; and 0.05% to D, where it is in default.

Using the Selenium script earlier to retrieve the Standard & Poor’s credit ratings, we can use the corporate bond's credit rating to determine the probability of a particular rating transitioning to D (default) during the next year according to the Standard & Poor’s 2019 transition matrix.

```python
# Will scrape the default probability for each rating

sp_rating_list = ['AAA','AA+','AA','AA-','A+','A','A-',
                  'BBB+','BBB','BBB-','BB+','BB','BB-',
                  'B+','B','B-']

ccc_list = ['CCC+','CCC','CCC-','CC+','CC','CC-','C+','C','C-']

sp_rating = None

for i in sp_rating_list:
    if bond_df_result['S&P'].iloc[0] == i:
        sp_rating = bond_df_result['S&P'].iloc[0]

if sp_rating == None:
    for i in ccc_list:
        if bond_df_result['S&P'].iloc[0] == i:
            sp_rating = 'CCC/C'

sp_transition_dp = 0

for i in range(33):
    if transition_matrix_df.loc[i][0] == sp_rating:
        sp_transition_dp += float(sp_clean_result_df.loc[i][18])

sp_transition_dp
```

    6.49

It appears that the market-implied probability of default we calculated for the nearest maturity corporate bond is close to the probability of default as determined from the historical data in the Standard & Poor’s 2019 transition matrix.

```python
# Compare the nearest maturity Market-implied probability of default with
# the historical probability of default in the Standard & Poor’s 2019 transition matrix
print("Market-implied probability of default = %s"%(bond_df_result['Probability of Default %'].iloc[0])+"%")
print("Standard & Poor’s probability of default = %s"%(sp_transition_dp)+"%")
```

    Market-implied probability of default = 4.21%
    Standard & Poor’s probability of default = 6.49%

### 3. Conclusion

In the example above, the bond valuation techniques using a Risk-adjusted Discount Rate does a reasonably good job at estimating the market-implied default probabilities. We calculated the Expected Cash Flow at each period by adding the product of the Default Payout and the Probability of Default (P) with the product of the promised payment (Coupon Payments and repayment of Principal) and the probability of not defaulting (1-P). One reason for any differences between historical and market-implied default probabilities is that historical default probabilities do not include the default risk premium associated with uncertainty over the timing of possible default loss.

The model used here is very sensitive to the discount and Recovery Rates selected. We assume a flat government bond yield curve, but it could be upward or downward sloping. If the government bond yield curve was sloped, the discount rates would need to be calculated sequentially by a process known as “bootstrapping.” We also assume in this example that the Recovery Rate is 40%, but another possibility is to change the assumed Recovery Rate to either 30% or 60% of exposure. Another simplifying assumption is that recovery is instantaneous. In practice, lengthy time delays can occur between the event of default and eventual recovery of cash. Notice that we assume that the Recovery Rate applies to interest as well as principal.

Also, we assume that default occurs only on coupon payment dates and that default will not occur on date 0, the current date. Although we assumed the annual default probability is the same each year, this does not need to be the case.

Even with the assumptions made in this analysis, the market-implied probability of default model built here does a fairly good job at identifying risk of corporate defaults and may suffice for simply rank ordering firms by credit worthiness.

### 4. Additional Reading and Code

*Bayesian Pairs Trading using Corporate Supply Chain Data*

If you liked this article, you may enjoy AlphaWave Data's [Bayesian Pairs Trading using Corporate Supply Chain Data](https://medium.com/@hdonnelly6/bayesian-pairs-trading-using-corporate-supply-chain-data-8b96305686d) article.  Using the [AlphaWave Data Corporate Supply Chain API](https://rapidapi.com/alphawave/api/corporate-supply-chain/endpoints), we can get a list of suppliers and customers for a given stock symbol.  You can further filter this list of suppliers and customers using the two-stage FCFF valuation model discussed in [Stock Valuation Using Free Cash Flow to the Firm With Python](https://hdonnelly6.medium.com/stock-valuation-using-free-cash-flow-to-the-firm-with-python-9a2f0e8f308f) to get a grouping of good pairs trading candidates that are potentially misvalued.  A list of company tickers that have supply chain data is included at the bottom of the Jupyter Notebooks available on [Google Colab](https://colab.research.google.com/drive/1e_SiiZn7WEW3OUNG-ftN3riPNjiz0M0C?usp=sharing) and [Github](https://github.com/AlphaWaveData/Jupyter-Notebooks/blob/master/AlphaWave%20Corporate%20Supply%20Chain%20API%20Example.ipynb), which could be a good list of tickers to run through the two-stage FCFF valuation model discussed further below.

*Stock Valuation Using Free Cash Flow to the Firm With Python*

You may also like [Stock Valuation Using Free Cash Flow to the Firm With Python](https://hdonnelly6.medium.com/stock-valuation-using-free-cash-flow-to-the-firm-with-python-9a2f0e8f308f) where we discuss how to value stocks using a two-stage Free Cash Flow to the Firm model using the [AlphaWave Data Financial Statements API](https://rapidapi.com/alphawave/api/financial-statements/endpoints) and the [AlphaWave Data Stock Analysis API](https://rapidapi.com/alphawave/api/stock-analysis/endpoints).  Jupyter Notebooks detailing this analysis are also available on [Google Colab](https://colab.research.google.com/drive/1BWmRIDtZGRndLk8lLGgpoURaAzHC8_jg?usp=sharing) and [Github](https://github.com/AlphaWaveData/Jupyter-Notebooks/blob/master/AlphaWave%20Stock%20Valuation%20using%20Free%20Cash%20Flow%20to%20the%20Firm%20example.ipynb).

```python

```

AlphaWave Market-Implied Probability of Default Example.ipynb


## EE 502 P: Analytical Methods for Electrical Engineering

# Homework 2: Sets, functions, and relations
## Due October 17, 2021 by 11:59 PM
### Mayank Kumar

Copyright © 2021, University of Washington

**Instructions**: Please use this notebook as a template. Answer all questions using well formatted Markdown with embedded LaTeX equations, executable Jupyter cells, or both. Submit your homework solutions as an `.ipynb` file via Canvas.

Although you may discuss the homework with others, you must turn in your own, original work.

**Things to remember:**
- Use complete sentences. Equations should appear in text as grammatical elements.
- Comment your code.
- Label your axes. Title your plots. Use legends where appropriate.
- Before submitting a notebook, choose Kernel -> Restart and Run All to make sure your notebook runs when the cells are evaluated in order.

Note : Late homework will be accepted up to one week after the due date and will be worth 50% of its full credit score.

### 0. Warmup (Do not turn in)

- Make sure you download and run the notebook for lecture 2. Work through the notebook, and see what happens when you change the expressions, and make up some of your own.
- Read chapter one of [An Introduction to Real Analysis](https://www.math.ucdavis.edu/~hunter/intro_analysis_pdf/intro_analysis.html) by John K. Hunter. You can skim the sections on index sets and infinite unions and intersections.
- Read up on [sets](https://www.w3schools.com/python/python_sets.asp), [tuples](https://www.w3schools.com/python/python_tuples.asp), and [lambdas](https://www.w3schools.com/python/python_lambda.asp) at python.org.

### 1. Set properties

Given the following definitions of sets

$$A = \{1,2,3\}$$
$$B = \{3,4,5\}$$
$$C = \{3,4,5,6,7\}$$

determine which of the following properties hold:

$$0 \in A$$

$$4 \in B \cap C$$

$$5 \in C-B$$

$$A \subseteq B$$

$$A \subseteq C$$

$$A \cap B \subseteq A$$

$$B \subseteq C$$

If the property holds, say why. If it does not hold, give a counterexample showing the definition is not satisfied.

___
### Answer starts from here
### Question 1
We have following sets to consider for answering questions:
$$A = \{1,2,3\}$$
$$B = \{3,4,5\}$$
$$C = \{3,4,5,6,7\}$$

**Property 1:**

**Answer:** No\
**Explanation:**\
Considering definition of set A, 0 does not belong to set A. Here "0" to part of set A, it has be an element of A. It should not be confused with NULL.\

**Counter Example:**
Set $\{\}$ would belong to A, or, if A was $\{0,1,2,3\}$ then this statement will hold true.
___

**Property 2:**

**Answer:** Yes \
**Explanation:**
$B \cap C = \{3,4,5\} $ \
Considering above, 4 is an element of $B \cap C$
___

**Property 3:**

**Answer:** No \
**Explanation:**
$5 \in C-B$ \
$ C-B = \{6,7\}$ : Here 5 is not part of the set C-B.
While calculating C-B, We consider all the elements which are part of B but not part of C.

**Counter Example:**
if we remove 5 from B, then this statement will hold true.
___

**Property 4:**

**Answer:** No \
**Explanation:**
$A \subseteq B$ \
3 is only element of A which is also available in B. the condition to be true we need all the elements of A must be in B.\
**Counter Example:** If A was $\{3,4\}$, this statement will hold true.
___

**Property 5:**

**Answer:** No \
**Explanation:**
$A \subseteq C$ \
3 is only element of A which is also available in C. If condition has to be true, all the elements of A must be in C. \
**Counter Example:** If A was $\{3,4,5\}$, this statement will hold true.

___
**Property 6:**

**Answer:** No \
**Explanation:**
$A \cap B \subseteq C $ \
$A \cap B = \{ 3\} $: Considering this, all the element which are part of $A \cap B $ are part of C. hence, it is true to say that statement holds true.
___

**Property 7:**

**Answer:** Yes \
**Explanation:**
$B \subseteq C$ to be true all the element of B should be available in C. In this case all the elements 3, 4 and 5 are part of set C. Hence, statement is true.

### 2. Set operations

Let $A = \{ 1,2,3,4,5 \}$ and $B = \{ 0,3,6 \}$. Find

a) $A \cup B$

b) $A \cap B$

c) $A - B$

d) $B - A$

Verify your results using Python sets.

```python
A = {1,2,3,4,5}
B = {0,3,6}
# a)
print("A union B(Manual):", {0,1,2,3,4,5,6})
print("A union B(Python):", A.union(B))

#b)
print("A intersection B(Manual):",{3})
print("A intersection B(Python):", A.intersection(B))

#c)
print("A minus B(Manual):", {1,2,4,5})
print("A minus B:(Python)", A.difference(B))

#d)
print("B minus A:", {0,6})
print("B minus A:", B.difference(A))

```

    A union B(Manual): {0, 1, 2, 3, 4, 5, 6}
    A union B(Python): {0, 1, 2, 3, 4, 5, 6}
    A intersection B(Manual): {3}
    A intersection B(Python): {3}
    A minus B(Manual): {1, 2, 4, 5}
    A minus B:(Python) {1, 2, 4, 5}
    B minus A: {0, 6}
    B minus A: {0, 6}

### 3. Set Proofs

Using the definitions of the set operations, the definition of the subset relation, and basic logic, show the following are true.

a) $A - B \subseteq A$

b) $A \cap (B-A) = \varnothing$

c) $A \cup (B-A) = A \cup B$

Show examples using small sets in Python illustrating each property.

___
### Solution to Question 3.
___
**a) $A - B \subseteq A$** \
Say,   $x \in A-B $        (if x belongs to A-B)\
 $\Rightarrow$   $ x \in A $ and $ x \notin B $  (by definition, if x belong to A it must not be part of B\
 as,  $x \in A $        (which implies that x will be part of A)\
  $\therefore$   $ A-B \subseteq A $

---
**b) $A \cap (B-A) = \varnothing$**

Say,   $ x \in B-A $ \
$\Rightarrow $   $ x \in B \;$ and $ \; x \notin A \; $ (by definition: if x belong to B, it must not be part of A)\

if,  $x \in B $   and   $x \notin A$.\
$\therefore$   $A \cap x = \varnothing$ \
Which proves that $A \cap (B-A) = \varnothing$

---
**c) $A \cup (B-A) = A \cup B$**

Say,  $x \in B-A $\
$\Rightarrow$   $ x \in B $ and  $ x \notin A$    (It implies that x is part of B but not A)

With B-A, We are removing the common element between B and A, \
So, x contains the element exclusively from B.

Hence, $A \cap x $ is same as $ A \cap B $
___

```python
A = {1,2,3,4,5}
B = {0,3,6}
# Question 3 (a)
C = A.difference(B)
print ("_______ Question 3(a) _______")
print ("A minus B = ", A.difference(B))
print ("Matrix A = ", A,"\n")

print ("_______ Question 3(b) _______")
print ("A minus B = ", A.intersection(B.difference(A)))
print ("Null = ", set(), "\n")

print ("_______ Question 3(c) _______")
print ("A minus B = ", A.union(B.difference(A)))
print ("Matrix A union B = ", A.union(B))

```

    _______ Question 3(a) _______
    A minus B =  {1, 2, 4, 5}
    Matrix A =  {1, 2, 3, 4, 5}

    _______ Question 3(b) _______
    A minus B =  set()
    Null =  set()

    _______ Question 3(c) _______
    A minus B =  {0, 1, 2, 3, 4, 5, 6}
    Matrix A union B =  {0, 1, 2, 3, 4, 5, 6}

### 4. Cartesian Products

a) If $A_i$ has $n_i$ elements, how many elements does $A_1 \times A_2 \times \dots A_n$ have? Why?

b) Give an example where the numbers of elements in $A_1 \times A_2 \times \dots A_n$ is 1.

c) Give examples of nonempty sets $A$ and $B$ where $A \times B = B \times A$.

___
#### Answer to Question 4 goes from here
**a)** Cardinality of such a case would be $\; n_1\;\times\;n_2\;\times\;n_3\;\times\;n_4\;\times... n_n $\
To start with, let us take cartesian product of two sets namely $A_1$ and $A_2$ with $n_1$ and $n_2$ elements respectively. Here cartesian product will be:
$$|A_1 \times A_2| = n_1 \times n_2$$

Similarly if consider cartesian product for 3 sets,
$$|A_1 \times A_2 \times A_3| = n_1 \times n_2 \times n_3$$

Similarly, extending this for n number of sets,
$$|A_1 \times A_2 \times A_3 \times ... A_n| = n_1 \times n_2 \times n_3\times ... n_n$$

**b)** Cardinality of cartesian product of n sets can be 1 if and only if all the sets have only one element.
i.e., $$|A_1 \times A_2 \times A_3 \times ... A_n| = 1 \iff |A_1| = |A_2| =|A_3| =...= |A_n| = 1 $$\
Example: $$A_1 = \{1\},\; A_2 = \{2\},\;A_3 = \{3\},\;....\;A_n = \{n\}$$

**c)** Case 1: $A \times B = B \times A \Rightarrow  A = B$ \
Case 2: $ A \times B = B \times A \Rightarrow A = \{\}$ and $B = \{\} $

if we are looking for non empty sets then, example:
$$ A = \{1,2,3\} , B = \{1,2,3\} $$
___

### 5. Function Properties

Plot each of the following functions from $\mathbb{Z}$ to $\mathbb{Z}$ over a representative subdomain (use points and not a line since the domain is $\mathbb{Z}$).
What is the range of each function? State which of them are injective, which are surjective, and which are bijective.
For functions for which a given property holds, explain why. For functions for which the given property does not hold, give a counterexample.

a) $f(n) = n-1$

b) $f(n) = n^3$

c) $f(n) = n^2 + 1$

___
### Answer to Question 5

a) $f(n) = n-1$ \
Range : $-\infty$  to  $\infty$
Injective  : Yes \
Surjective : Yes \
Bijective  : Yes

b) $f(n) = n^3$\
Range : $-\infty$  to  $\infty$ \
Injective  : Yes \
Surjective : Yes \
Bijective  : Yes

c) $f(n) = n^2 + 1$ \
Range : 1 to $\infty$ \
Injective  : No \
Surjective : No \
Bijective  : No
Range is not equal to co-domain in this case.\
Counter example: if we change the co-domain to 1 to $\infty$, function will become Surjective.
if we change the domain to positive numbers (along with codomain 1 to $\infty$), function will become bijective.
___

```python
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline

x = np.linspace(-500,500,1000)
fig,ax = plt.subplots(1,2, figsize = (15,5))
fig1,ax1 = plt.subplots(1,1, figsize = (15,5))

#Defining first function from the question
def F(x):
    return x-1

ax[0].plot(x,F(x), color = 'red')             #plot x-1
ax[0].set_title('$f(x) = x-1$')

#Defining second function from the question
def F1(x):
    return x**3

ax[1].plot(x,F1(x), color = 'green')          #plot x^3
ax[1].set_title("$f(x) = x^3$")

#Defining third function from the question
def F2(x):
    return (x**2 + 1)

ax1.plot(x,F2(x), color = 'blue')             #Plot x^2 + 1
ax1.set_title("$f(x) = x^2 + 1$")
```

### 6. Composition

a) Suppose that $f(x) = x^2 + 1$ and $g(x) = e^x$ are functions from $\mathbb{R}$ into $\mathbb{R}$. Find $f \circ g$ and $g \circ f$ and plot them in Python (on the same axis to compare).

b) Suppose $f(x) = a x + b$ and $g(x) = c x + d$ are functions from $\mathbb{R}$ into $\mathbb{R}$. Find constants $a$, $b$, $c$ and $d$ such that $f \circ g = g \circ f$.

```python
import numpy as np
import math
from sympy import *
init_printing(use_latex='mathjax')

################################## Question 6 (a) ####################################

def G(x):                              #declaration for Function G
    return round(math.exp(x),3)

#Declaration for Function F
def F(x):                              #declaration for Function F
    return x**2 + 1

def compose(F, G):                     #composing the function to generate a composite function
    return lambda x: F(G(x))

domain = np.linspace(-1.5,1.5,1000)    #defining a domain for ploting the function

FOG = compose(F,G)
GOF = compose(G,F)

fig,ax = plt.subplots(1,1,figsize = (14,7))
ax.set_title("FOG and GOF")
count = 0

#ploting the function FOG and GOF
for x in domain:
    if count == 0:
        ax.plot(x, FOG(x), "o",label = "FOG", color = 'red')
        ax.plot(x, GOF(x), "o",label = "GOF", color = "blue")
        count += 1

    elif count >= 1:
        ax.plot(x, FOG(x), "o",color = 'red')
        ax.plot(x, GOF(x), "o",color = "blue")

fig.legend()

```

### Question 6 (b)
$F = ax + b $\
$G = cx + d $

$FOG = acx + ad + b $\
$GOF = acx + bc + d $

if $FOG = GOF$ \
$\Rightarrow acx + ad + b = acx + bc + d $\
$\Rightarrow ad + b = bc + d $\
$\Rightarrow b(1-c) = d(1-a)$

$\Rightarrow \frac {b}{1-a} = \frac {d}{1-c} $

Considering above, $a \neq 1 \;and\; c \neq 1$

If we substitute $a = 2,\;\;\; -b = \frac{d}{1-c} \; \;\;\;...(i) $

from $(i), \;if \;\;c = 2,\;\; b = d  $\
$\therefore a=c$ & $ b=d $

we have $a = 2, b = 3, c = 2, d = 3$

F = 2x + 3 \
G = 2x + 3

### 7. Relations

Define the relation $R$ on $\mathbb{N} \times \mathbb{N}$ saying that $x \; R\; y$ if and only if the binary representations of $x$ and $y$ have the same number of ones. For example, $15 \; R \; 23$ since $15$ in binary is $1111$ and $23$ in binary is $10111$, which both have four ones.

Show that $R$ is an equivalence relation.

```python
def Dec2Bin(x):
    """
    Function to convert decimal to binary.
    output is list containing bianry representation.

    index 0 will have most significant digit of the bianry representation.
    """
    if x == 0: return [0]       #if number is 0, return 0.
    y = []                      #declare a empty list, this will be used to append the respective values.
    while x:
        y.append(x%2)
        x >>= 1
    return y[::-1]              #reversing the list to maintain the most significant bit at index "0"

def countOne(L):
    """
    counts number of 1 in a list.
    this function assumes that entry is list of 0 and 1.
    However in any condition if list element is 1, it will count and return.
    """
    N = 0
    for i in range(len(L)):
        if L[i] == 1:
            N += 1
    return N

n=100          #this will limit the range of x and y to 1 to 99. to check for relations
               #beyond that please update the value of n

R = {(x,y) for x in range(1,n) for y in range (1,n) if countOne(Dec2Bin(x)) == countOne(Dec2Bin(y)) }

#checking for the values of x and y, x =15, y = 23
print ("are (15,23) related? : ", (15,23) in R)

#####################################################################################
# a relation is equivalence if it is symmetric, transitive and reflexive

# defining a function to check a pair of numbers are transitive.
def transitive(R):
    for a,b in R:
        for c,d in R:
            if b==c and (a,d) not in R:
                return False
    return True

#defining a function to check symmetricity of a relation
def symmetric(R):
    for a,b in R:
        for c,d in R:
            if b==c and a==d:
                return True
    return False

def reflexive(R):
    for a,b in R:
        if a==b and (a,b) not in R:
            return False
    return True

T = transitive(R)
S = symmetric(R)
Ref = reflexive(R)

if (T ==True and S == True and Ref == True):
    print("\nReflexive: ", Ref)
    print("Transitive: ", T)
    print("Symmetric: ", S)
    print("\nGiven relation R is Equivalence")
```

    are (15,23) related? :  True

    Reflexive:  True
    Transitive:  True
    Symmetric:  True

    Given relation R is Equivalence

### 8. Sets, Functions, and Relations in Python

Express each of the following objects in Python.

a) The set of $P$ prime numbers less than 100.

b) The function $f: \{1,2,3,4,5,6\} \rightarrow \{0,1\}$ in which $f(x) = 0$ if $x$ is even and $f(x)=1$ if $x$ is odd, expressed as a dictionary.

```python
#declare a function to check if a given number is prime

def isPrime(n,i=2):                #input arguments are n = number and i = index for recursion
    if (n == 1 or n == 0):         #returns False if input number is 0 or 1
        False

    if ( n == i):                 #if the number is 2 it return true
        return True

    if (n%i == 0):              #for numbers > 2 dividing with all the numbers till it get 0.
        return False

    i = i+1
    return isPrime(n,i)

n = 100                           #it doesnot include 100, hence will consider numbers less than 100.

R = {(x) for x in range (2,n) if isPrime(x,2) == True}
print("Prime numbers less than %d are: " %n,R)

############################# Part 2 #################

#### Declare a general function to generate a dictionary in which even place has value = 0 and odd has value = 1
def funcMap(n):
    """
    it returns a dictionary with key starting with 1 to n.
    if key is odd, value will be 0
    if key is even, value will be 1
    it will return dictionary with n elements.
    """
    n = n + 1
    F = {}             #declare and empty dictionary
    for i in range (1,n):
        F[i] = i%2
    return F

# function call for key 1 to 6.
FofX = funcMap(6)
print("\nHere goes the function: ",FofX)
FofX[5]
```

    Prime numbers less than 100 are:  {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}

    Here goes the function:  {1: 1, 2: 0, 3: 1, 4: 0, 5: 1, 6: 0}

$\displaystyle 1$

```python

```

Sets, Functions, and Relations/SetFunctionAndRelations.ipynb


# Table of Contents

1  Practice Problems

1.1  2E1.

1.2  2E2.

1.3  2E3.

1.4  2E4.

1.5  2M1.

1.6  2M2.

1.7  2M3.

1.8  2M4.

1.9  2M5.

1.10  2M6.

1.11  2M7.

1.12  2H1.

1.13  2H2.

1.14  2H3.

1.15  2H4.

## Import Statements

```python
import pymc3 as pm
import numpy as np
import scipy.stats as stats
import matplotlib.pyplot as plt
```

## Helper Functions

```python
def posterior_grid_approx(prior, success=6, tosses=9):
    """
        This function helps calculate a grid approximation of the posterior distribution.

        Parameters:
            prior: np.array
                A distribution representing our state of knowledge before seeing the data.
                Number of items should be the same as number of grid points.

            success: integer
                Number of successes.

            tosses: integer
                Number of tosses (i.e. successes + failures).

        Returns:
            p_grid: np.array
                Evenly-spaced out grid between 0 and 1.

            posterior: np.array
                The posterior distribution.

    """
    # define grid
    p_grid = np.linspace(0, 1, prior.shape[0])

    # compute likelihood at each point in the grid
    likelihood = stats.binom.pmf(success, tosses, p_grid)

    # compute product of likelihood and prior
    unstd_posterior = likelihood * prior

    # standardize the posterior, so it sums to 1
    posterior = unstd_posterior / unstd_posterior.sum()
    return p_grid, posterior

def grid_approx_plot(
    w=6,
    n=9,
    prior=np.repeat(5,100),
    x_label='probability of water'
):
    """
        This function helps calculate a grid approximation of the posterior distribution,
        and then plots it.

        Parameters:
            prior: np.array
                A distribution representing our state of knowledge before seeing the data.
                Number of items should be the same as number of grid points.

            w: integer
                Number of successes.

            n: integer
                Number of trials.

    """
    p_grid, posterior = posterior_grid_approx(
        success=w,
        tosses=n,
        prior=prior
    )
    plt.plot(p_grid, posterior, 'o-', label='success = {}\ntosses = {}'.format(w, n))
    plt.xlabel(x_label)
    plt.ylabel('posterior probability')
#     plt.title('{} points'.format(points))
    plt.legend(loc=0)

    return p_grid, posterior
```

# Practice Problems

## 2E1.

Which of the expressions below correspond to the statement: _the probability of rain on Monday_?

(1) $Pr(rain)$
* Nope. This is the averaged probability of rain.

(2) $Pr(rain\mid Monday)$
* Yes. Given that it is Monday, what is the probability of rain?

(3) $Pr(Monday \mid rain)$
* No. This is the probability of being Monday given that it is raining.

(4) $Pr(rain, Monday) / Pr(Monday)$
* Yes. This is equivalent to the second option.

## 2E2.

Which of the expressions below correspond to the expression: $Pr(Monday \mid rain)$?

(1) The probability of rain on Monday.
* No. This is $Pr(rain \mid Monday)$.

(2) The probability of rain, given that it is Monday.
* No. This is $Pr(rain \mid Monday)$.

(3) The probability that it is Monday, given that it is raining.
* Yes. This is $Pr(Monday \mid rain)$.

(4) The probability that it is Monday and that it is raining.
* No. This is $Pr(Monday, rain)$.

## 2E3.

Which of the expressions below correspond to the statement:  _the probability that it is Monday, given that it is raining_?

(1) $Pr(Monday \mid rain)$
* Yes. By definition.

(2) $Pr(rain \mid Monday)$
* No. This is probability of rain given that it is a Monday.

(3) $Pr(rain\mid Monday)Pr(Monday)$
* No. This is equivalent to $Pr(rain, Monday)$, or the probability that it is raining and it is Monday.

(4) $Pr(rain\mid Monday)Pr(Monday) / Pr(rain)$
* This is equivalent to $Pr(rain, Monday) / Pr(rain)$, which then simplifies to $Pr(Monday \mid rain)$. So yes.

(5) $Pr(Monday \mid rain)Pr(rain) / Pr(Monday)$
* This simplifies to $Pr(Monday, rain) / Pr(Monday) = Pr(rain \mid Monday)$, so nope.

## 2E4.

The Bayesian statistician Bruno de Finetti (1906-1985) began his book on probability theory with the declaration: "PROBABILITY DOES NOT EXIST." The capitals appeared in the original, so I imagine de Finetti wanted us to shout this statement. What he meant is that probabilty is a device for describing uncertainty from the perspective of an observer with limited knowledge; it has no objective reality. Discuss the globe tossing example from the chapter, in light of this statement. What does it mean to say "the probability of water is 0.7?"

Ans:

I think he meant that probability only exists in the "small world." It represents a person's state of uncertainty on some aspect of the real world. For example, in the real world, water is objectively some proportion of the whole Earth. The true proportion of water in Earth is probably some precise number, for example: 0.712345678... However, when a Bayesian says that "the probability of water is 0.7," this implies that this person _believes_ the ratio is about 0.7. The person is betting that the ratio is close to 0.7.

## 2M1.

Recall the globe tossing model from the chapter. Compute and plot the grid approximate posterior distribution for each of the following sets of observations. In each case, assume a uniform prior _p_.

(1) W,W,W

```python
_, _ = grid_approx_plot(n=3,w=3, prior=np.repeat(5,int(1e3)) )
```

(2) W,W,W,L

```python
_,_ = grid_approx_plot(n=4, w=3, prior=np.repeat(5,int(1e3)) )
```

(3) L,W,W,L,W,W,W

```python
_, _ = grid_approx_plot(n=7, w=5, prior=np.repeat(5,int(1e3)))
```

## 2M2.

Now assume a prior for _p_ that is equal to zero when $p < 0.5$ and is a positive constant when $p >= 0.5$. Again, compute and plot the grid approximate posterior distribution for each of the sets of observations in the problem just above.

```python
_, _ = grid_approx_plot(
    n=7,
    w=5,
    prior=( np.linspace(0, 1, int(1e3)) >= 0.5).astype(int))
```

## 2M3.

Suppose there are two globes, one for Earth and one for Mars. The Earth globe is 70% covered in water. The Mars globe is 100% land. Further suppose that one of these globes--you don't know which--was tossed in the air and produced a "land" observation. Assume that each globe was equally likely to be tossed. Show that the posterior probability that the globe was the Earth, conditional on seeing "land" $Pr(\text{Earth}\mid\text{land})$ is 0.23.

$Pr(\text{water} \mid \text{Earth}) = 0.7$

$Pr(\text{land} \mid \text{Earth}) = 0.3$

$Pr(\text{Earth}) = 0.5$

$Pr(\text{land} \mid \text{Mars}) = 1.0$

$Pr(\text{Mars}) = 0.5$

\begin{equation}
\begin{aligned}
    Pr(\text{land}) &= Pr(\text{land} \mid \text{Earth})Pr(\text{Earth}) + Pr(\text{land} \mid \text{Mars})Pr(\text{Mars}) \\
    &= 0.3 * 0.5 + 1.0 * 0.5 \\
    &= 0.65
\end{aligned}
\end{equation}

\begin{equation}
\begin{aligned}
    Pr(\text{Earth} \mid \text{land}) &= \frac{0.3 * 0.5}{0.65} \\
    &= 0.23 \\
\end{aligned}
\end{equation}

## 2M4.

Suppose you have a deck with only three cards. Each card has two sides, and each side is either black or white. One card has two black sides. The second card has one black and one white side. The third card has two white sides. Now suppose all three cards are placed in a bag and shuffled. Someone reaches into the bag and pulls out a card and places it flat on a table. A black side is shown facing up, but you don't know the color of the side facing down. Show that the probability that the other side is also black is 2/3. Use the counting method (Section 2 of the chapter) to approach this problem. This means counting up the ways that each card could produce the observed data (a black side facing up on the table).

Note: $B$ stands for black and $W$ stands for white. $B_1$ means that side 1 of a card is black. The left side is the side facing up (e.g. $B_2 \mid B_1$ means that the second side is black and it is the one facing up, while the other side is also black).

Here are the combinations:

$B_1 \mid B_2$ Black side is facing up and other side is black

$B_2 \mid B_1$ Black side is facing up and other side is black

$B_1 \mid W_2$ Black side is facing up, but other side is white.

$W_2 \mid B_1$ Not relevant, since white side up.

$W_1 \mid W_2$ Not relevant, since white side up.

$W_2 \mid W_1$ Not relevant, since white side up.

There are three events consistent with "Black side facing up," and only two of them are consistent with the the event "other side is also black." Thus the probability that the other side is black, given that the known side is black is $2/3$.

## 2M5.

Now suppose there are four cards: B/B, B/W, W/W, and another B/B. Again suppose a card is drawn from the bag and a black side appears face up. Again calculate the probability that the other side is black.

Previously:

$B_1 \mid B_2$ Black side is facing up and other side is black

$B_2 \mid B_1$ Black side is facing up and other side is black

$B_1 \mid W_2$ Black side is facing up, but other side is white.

$W_2 \mid B_1$ Not relevant, since white side up.

$W_1 \mid W_2$ Not relevant, since white side up.

$W_2 \mid W_1$ Not relevant, since white side up.

New Data:

$B_1 \mid B_2$ Black side is facing up and other side is black

$B_2 \mid B_1$ Black side is facing up and other side is black

There are now five events consistent with "Black side facing up," and four of them are consistent with the the event "other side is also black," so the probability of the other side being black, given that the side being shown is black is $4/5$.

## 2M6.

Imagine that the black ink is heavy, and so cards with black sides are heavier than cards with white sides. As a result, it's less likely that a card with black sides is pulled from the bag. So again assume there are three cards: B/B, B/W, and W/W. After experimenting a number of times, you conclude that for every way to pull the B/B card from the bag there are 2 ways to pull the B/W card and 3 ways to pull the W/W card. Again suppose that a card is pulled and a black side appears face up. Show that the probability the other side is black is now 0.5. Use the counting method, as before.

A probabilistically equal statement to this is if we pretend to have the bag have one $B/B$ card, two $B/W$ and three $W/W$ card in the bag.

$B/B$ gives us two ways of picking a black side up: $B_1 / B_2$ and $B_2 / B_1$.

If we pick one of the $B/W$ cards, there is one way that a card has black side up: $B_1$. However, because picking up a $B/W$ is twice as likely as picking up a $B/B$, then there are $2\times 1 = 2$ ways to get a card where we know that one side is black.

There are $4$ total ways of picking a black card, but only half of them has black on the other side. Therefore the probability that the other side is black, given that a black side is face up, is 0.5.

## 2M7.

Assume again the original card problem, with a single card showing a black side face up. Before looking at the other side, we draw another card from the bag and lay it face up on the table. The face that is shown on the new card is white. Show that the probability that the first card, the one showing a black side, has black on its other side is now 0.75. Use the counting method, if you can. Hint: Treat this like the sequence of globe tosses, counting all the ways to see each observation, for each possible first card.

$B_1 \mid B_2$ -> $W_1 \mid B_2$ Black on the other side.

$B_1 \mid B_2$ -> $W_1 \mid W_2$ Black on the other side.

$B_1 \mid B_2$ -> $W_2 \mid W_1$ Black on the other side.

$B_2 \mid B_1$ -> $W_1 \mid B_2$ Black on the other side.

$B_2 \mid B_1$ -> $W_1 \mid W_2$ Black on the other side.

$B_2 \mid B_1$ -> $W_2 \mid W_1$ Black on the other side.

$B_1 \mid W_2$ -> $W_1 \mid W_2$ Not black on the other side.

$B_1 \mid W_2$ -> $W_2 \mid W_1$ Not black on the other side.

Given that the second card has white face-up and the first card has black face-up, the probability that the first card's other side is black is 0.75.

## 2H1.

Suppose there are two species of panda bear. Both are equally common in the wild and live in the same places. They look exactly alike and eat the same food, and there is yet no genetic assay capable of telling them apart. They differ however in their family sizes. Species A gives birth to twins 10% of the time, otherwise birthing a single infant. Species B births twins 20% of the time, otherwise birthing singleton infants. Assume these numbers are known with certainty, from many years of field research.

Now suppose you are managing a captive panda breeding program. You have a new female panda of unknown species, and she has just given birth to twins. What is the probability that her next birth will also be twins?

Note: $C_1=2$ stands for twins during the first birthing event, $C_2=1$ stands for a singleton infant during the second birthing event. $S=a$ means that the species which gave birth was from Species A.

$P(C_1=2 \mid S=a) = 0.1$

$P(C_1=1 \mid S=a) = 0.9$

$P(C_1=2 \mid S=b) = 0.2$

$P(C_1=1 \mid S=b) = 0.8$

$P(S=a) = 0.5$

$P(S=b) = 0.5$

$$
\begin{equation}
    \begin{aligned}
        P(S=a \mid C_1=2) &= \frac{P(C_1=2 \mid S=a)P(S=a)}{P(C_1=2)} \\
        &= \frac{0.05}{0.05+0.1} \\
        &= \frac{1}{3} \\
    \end{aligned}
\end{equation}
$$

$$
\begin{equation}
    \begin{aligned}
        P(S=b \mid C_1=2) &= 1 - P(S=a \mid C_1=2) \\
        &= \frac{2}{3}
    \end{aligned}
\end{equation}
$$

$$
\begin{equation}
    \begin{aligned}
        P(C_2=2 \mid C_1=2) &= \sum_S P(C_2=2, S, \mid C_1=2) \\
        &= P(C_2=2, S=a \mid C_1=2) + P(C_2=2, S=b \mid C_1=2) \\
        &= P(C_2=2 \mid S=a, C_1=2) \cdot P(S=a \mid C_1=2) \\
        &\quad+ P(C_2=2 \mid S=b, C_1=2) \cdot P(S=b \mid C_1=2) \\
        &= P(C_2=2 \mid S=a) \cdot P(S=a \mid C_1=2) \\
        &\quad+ P(C_2=2 \mid S=b) \cdot P(S=b \mid C_1=2) & \text{Conditional independence. See Note below}\\
        &= \frac{1}{10} \times \frac{1}{3} + \frac{2}{10} \times \frac{2}{3} \\
        &= \frac{1}{30} + \frac{4}{30} \\
        &= \frac{1}{6}
    \end{aligned}
\end{equation}
$$

_Note_: The causal diagram implied here is the following:

The causal diagram implies that if we already know the Species ($S$), then Birth at Time 1 ($C_1$) and Birth at Time 2 ($C_2$) are independent from each other. In mathematical notation:

$$ C_2 \mathrel{\unicode{x2AEB} C_1 \mid S}$$

In other words, if we know the species, knowing about the birth at time 1 does not give us any more information about birth at time 2. Therefore, we have the license to remove $C_1$ from the conditioning section:

$$
\begin{equation}
    \begin{aligned}
         P(C_2=2 \mid S=a, C_1=2) &= P(C_2=2 \mid S=a) \\
         P(C_2=2 \mid S=b, C_1=2) &= P(C_2=2 \mid S=b) \\
    \end{aligned}
\end{equation}
$$

## 2H2.

Recall all the facts from the problem above. Now compute the probability that the panda we have is from species A, assuming we have observed only the first birth and that it was twins.

$$
\begin{equation}
    \begin{aligned}
        P(S=a \mid C_1=2) &= \frac{P(C_1=2 \mid S=a)P(S=a)}{P(C_1=2)} \\
        &= \frac{0.05}{0.05+0.1} \\
        &= \frac{1}{3} \\
    \end{aligned}
\end{equation}
$$

## 2H3.

Continuing on from the previous problem, suppose the same panda mother has a second birth and that it is not twins, but a singleton infant. Compute the posterior probability that this panda is species A.

$$
\begin{equation}
    \begin{aligned}
        P(S=a \mid C_2=1, C_1=2) &= \frac{P(C_2=1, C_1=2 \mid S=a)P(S=a)}{P(C_2=1, C_1=2)} \\
        &= \frac{P(C_2=1 \mid S=a)P(C_1=2 \mid S=a)P(S=a)}{P(C_2=1, C_1=2)} \\
        &= \frac{P(C_2=1 \mid S=a)P(C_1=2 \mid S=a)P(S=a)}{P(C_2=1 \mid S=a)P(C_1=2 \mid S=a)P(S=a) + P(C_2=1 \mid S=b)P(C_1=2 \mid S=b)P(S=b)} \\
        &= \frac{0.9 \times 0.1 \times 0.5}{0.9 \times 0.1 \times 0.5 + 0.8 \times 0.2 \times 0.5} \\
        &= 0.36
    \end{aligned}
\end{equation}
$$

## 2H4.

A common boast of Bayesian statisticians is that Bayesian inference makes it easy to use all the data, even if the data are of different types.

So suppose now that a veterinarian comes along who has a new genetic test that she claims can identify the species of our mother panda. But the test, like all tests, is imperfect. This in the information you have about the test:

* The probability it correctly identifies a species A panda is 0.8.
* The probability it correctly identifies a species B panda is 0.65.

The vet administers the test to your panda and tells you that the test is positive for species A. First ignore your previous information from the births and compute the posterior probability that your panda is species A. Then redo your calculation now using the birth data as well.

Let $T$ stand for the test result.

$P(T=a \mid S=a) = 0.8$

$P(T=b \mid S=b) = 0.65$, therefore: $P(T=a \mid S=b) = 0.35$.

Without birth data:

$$
\begin{equation}
    \begin{aligned}
        P(S=a \mid T=a) &= \frac{P(T=a \mid S=a)P(S=a)}{P(T=a)} \\
        &= \frac{P(T=a \mid S=a)P(S=a)}{P(T=a \mid S=a)P(S=a) + P(T=a \mid S=b)P(S=b)} \\
        &= \frac{0.8 \times 0.5}{0.8 \times 0.5 + 0.35 \times 0.5} \\
        &= \frac{0.8}{1.15} \\
        &\approx 0.70
    \end{aligned}
\end{equation}
$$

With birth data:

We use the posterior of the previous answer $P(S=a \mid C_2=1, C_1=2) = 0.36$ as the new prior $P(S=a)$:

$$
\begin{equation}
    \begin{aligned}
        P(S=a \mid T=a) &= \frac{P(T=a \mid S=a)P(S=a)}{P(T=a)} \\
        &= \frac{P(T=a \mid S=a)P(S=a)}{P(T=a \mid S=a)P(S=a) + P(T=a \mid S=b)P(S=b)} \\
        &= \frac{0.8 \times 0.36}{0.8 \times 0.36 + 0.35 \times 0.64} \\
        &\approx 0.56
    \end{aligned}
\end{equation}
$$