Analyzing Income Statements

Understand profitability and performance from revenues to profits.

30 min read
Beginner

Introduction to Income Statements

Now that we understand the role of financial statements, we’ll begin with the one investors use most often: the income statement.

The income statement explains how a business performed over a period of time, such as a quarter or a year.

At its core, it answers one simple question:

Did the company make more money than it spent?

Rather than freezing the business at a single moment, the income statement follows money as it flows in, gets spent, and eventually turns into profit (or loss).

In this lesson, we’ll rebuild an income statement step by step and mirror each line using Python so the logic becomes concrete.

Example: Annual Income Statement

To ground the discussion, we’ll work with a simplified annual income statement for a fictional company.

We’ll return to this same example throughout the lesson so you can see how each line connects to the next.

Annual Income Statement (USD)
Item
Amount (USD)
Revenue1,000,000
Cost of Goods Sold (COGS)600,000
Gross Profit400,000
Operating Expenses200,000
Operating Profit200,000
Interest Expense30,000
Taxes50,000
Net Income120,000

We’ll start by storing these values in Python so we can work with them programmatically.

python
income_statement = {
    "revenue": 1_000_000,
    "cogs": 600_000,
    "operating_expenses": 200_000,
    "interest_expense": 30_000,
    "taxes": 50_000
}

income_statement

Revenue: Where Everything Starts

Revenue represents the total money earned from selling products or services.

Revenue=Total Sales\text{Revenue} = \text{Total Sales}

Every income statement begins here. In our example, revenue is $1,000,000.

python
revenue = income_statement["revenue"]
revenue

Costs and Gross Profit

Cost of Goods Sold (COGS) includes the direct costs required to produce what the company sells.

Subtracting COGS from revenue gives us gross profit.

Gross Profit=Revenue−COGS\text{Gross Profit} = \text{Revenue} - \text{COGS}
python
cogs = income_statement["cogs"]
gross_profit = revenue - cogs
gross_profit

Gross profit tells us whether the core product or service is economically viable before considering overhead.

Gross Margin: Profitability at the Product Level

Gross profit shows the absolute amount left after production costs.

Gross margin answers a more scalable question: How much of each dollar of revenue turns into gross profit?

Gross Margin=Gross ProfitRevenue\text{Gross Margin} = \frac{\text{Gross Profit}}{\text{Revenue}}
python
gross_margin = gross_profit / revenue
gross_margin

A 40% gross margin means the company keeps 40 cents from every dollar before operating expenses.

This is where pricing power and production efficiency show up.

Running the Business: Operating Profit

Operating expenses are the ongoing costs required to run the business – such as marketing, administration, and R&D.

Subtracting these from gross profit gives us operating profit.

Operating Profit=Gross Profit−Operating Expenses\text{Operating Profit} = \text{Gross Profit} - \text{Operating Expenses}
python
operating_expenses = income_statement["operating_expenses"]
operating_profit = gross_profit - operating_expenses
operating_profit

Operating Margin: How Efficient Is the Business?

Operating profit reflects earnings from core operations.

To compare businesses of different sizes, we express it as operating margin.

Operating Margin=Operating ProfitRevenue\text{Operating Margin} = \frac{\text{Operating Profit}}{\text{Revenue}}
python
operating_margin = operating_profit / revenue
operating_margin

A 20% operating margin means the company keeps 20 cents per dollar after covering production and operating costs.

This is often used as a proxy for management efficiency.

EBITDA: Profit Before Accounting Charges

Operating profit already tells us a lot about business efficiency.

However, analysts often go one step further by removing non-cash accounting charges like depreciation and amortization.

This gives us EBITDA:

EBITDA=Operating Profit+Depreciation+Amortization\text{EBITDA} = \text{Operating Profit} + \text{Depreciation} + \text{Amortization}

EBITDA approximates cash generated by core operations before financing, taxes, and asset-related accounting effects.

For simplicity, assume the company recorded:

  • Depreciation: $40,000
  • Amortization: $20,000
python
depreciation = 40_000
amortization = 20_000

ebitda = operating_profit + depreciation + amortization
ebitda

EBITDA is not a cash flow metric but it often serves as a bridge between the income statement and the cash flow statement.

EBITDA Margin: Operating Profitability Before Asset Effects

Like other profit figures, EBITDA becomes more useful when expressed as a margin.

EBITDA Margin=EBITDARevenue\text{EBITDA Margin} = \frac{\text{EBITDA}}{\text{Revenue}}
python
ebitda_margin = ebitda / revenue
ebitda_margin

An EBITDA margin of 26% means the business generates 26 cents of operating earnings per dollar of revenue before depreciation, amortization, interest, and taxes.

This metric is especially useful when comparing companies with different asset bases or accounting policies.

Interest, Taxes, and the Bottom Line

After operating profit, we account for financing costs and taxes.

What remains is net income, also known as the bottom line.

Net Income=Operating Profit−Interest−Taxes\text{Net Income} = \text{Operating Profit} - \text{Interest} - \text{Taxes}
python
interest = income_statement["interest_expense"]
taxes = income_statement["taxes"]

net_income = operating_profit - interest - taxes
net_income

This matches the net income shown in the income statement table.

Interest Coverage Ratio: Can the Business Service Its Debt?

Profitability alone isn’t enough.

A company must generate sufficient operating profit to meet its financing obligations. The interest coverage ratio measures this directly.

Interest Coverage Ratio=Operating ProfitInterest Expense\text{Interest Coverage Ratio} = \frac{\text{Operating Profit}}{\text{Interest Expense}}
python
interest_coverage = operating_profit / interest
interest_coverage

An interest coverage ratio of 6.67 means the company earns nearly seven times its interest expense from operations.

This suggests a comfortable ability to service debt.

As a general guide:

  • Below 2.0 can signal financial stress
  • 3.0–5.0 is often considered adequate
  • Very high ratios may indicate underutilized leverage

The right level depends on business stability and cash flow predictability.

What the Income Statement Tells Us

Once constructed, the income statement becomes a powerful analytical tool.

One common metric is net margin, which shows how much revenue ultimately turns into profit.

Net Margin=Net IncomeRevenue\text{Net Margin} = \frac{\text{Net Income}}{\text{Revenue}}
python
net_margin = net_income / revenue
net_margin

A net margin of 12% means the company keeps 12 cents as profit from every dollar it earns.

Seeing All Margins Together

Each level of profit tells a different story.

Viewing margins side by side helps us understand where value is created – or lost.

python
margins = {
    "Gross Margin": gross_margin,
    "Operating Margin": operating_margin,
    "Net Margin": net_margin
}

margins

Margins shrink as more costs are included.

Healthy businesses tend to show consistency across these layers.

Margins as Return on Sales

All the margins we’ve calculated share the same basic structure:

Return on Sales=ProfitRevenue\text{Return on Sales} = \frac{\text{Profit}}{\text{Revenue}}

The only difference is which layer of profit we use.

  • Gross margin measures return after production costs
  • Operating margin measures return after running the business
  • EBITDA margin measures return before asset-related accounting effects
  • Net margin measures what ultimately belongs to shareholders

Each margin strips away a different category of cost.

Thinking in terms of return on sales helps clarify that margins are not competing metrics – they are different lenses on the same economic story.

Understanding the Cost Structure

Margins decline because different types of costs consume revenue.

Breaking each cost into a percentage helps explain why profits look the way they do.

python
cost_structure = {
    "COGS % of Revenue": cogs / revenue,
    "Operating Expenses % of Revenue": operating_expenses / revenue,
    "Interest % of Revenue": interest / revenue,
    "Taxes % of Revenue": taxes / revenue
}

cost_structure

This perspective explains how two companies with similar revenue can end up with very different profitability.

Looking at More Than One Year

An income statement becomes far more insightful when viewed across time.

This allows us to ask:

Is the business improving year after year?
Net Income Over Three Years (USD)
Year
Net Income
Year 167,000
Year 295,000
Year 3116,000

Even without calculations, we can see profits rising.

Let’s represent the same data in Python.

python
years = ["Year 1", "Year 2", "Year 3"]
net_income = [67_000, 95_000, 116_000]

list(zip(years, net_income))

Measuring Profit Growth Over Time

Year-by-year profits show direction.

Growth rates show speed.

Growth Rate=Current Profit−Previous ProfitPrevious Profit\text{Growth Rate} = \frac{\text{Current Profit} - \text{Previous Profit}} {\text{Previous Profit}}
python
growth_rates = []

for i in range(1, len(net_income)):
    growth = (net_income[i] - net_income[i-1]) / net_income[i-1]
    growth_rates.append(growth)

[round(g * 100, 1) for g in growth_rates]

Profits are still growing, but at a slowing pace.

This pattern often signals a maturing business.

Comparing Two Companies

Income statements also allow direct comparisons.

Here are two companies over the same period with very different trajectories.

Net Income Comparison (USD)
Year
Company A
Company B
Year 167,00020,000
Year 295,0008,000
Year 3116,000-12,000

Company A improves steadily.

Company B deteriorates and eventually becomes unprofitable.

python
company_a = [67_000, 95_000, 116_000]
company_b = [20_000, 8_000, -12_000]

years = ["Year 1", "Year 2", "Year 3"]

list(zip(years, company_a, company_b))

Comparing Profitability, Not Just Profits

Absolute profit numbers can be misleading.

To compare fairly, we focus on net margin.

python
revenue_a = 1_000_000
revenue_b = 1_000_000

net_margin_a = [ni / revenue_a for ni in company_a]
net_margin_b = [ni / revenue_b for ni in company_b]

list(zip(years, net_margin_a, net_margin_b))

Company B isn’t just earning less – it’s becoming structurally unprofitable.

Margins reveal business quality far more clearly than raw profit numbers.

Wrapping It All Together

In this lesson, we built the income statement from the ground up.

We started with revenue, followed the money through costs, and saw how it eventually became profit. Along the way, we translated each line into Python and used margins to understand profitability at different layers of the business.

By the end, the income statement stopped being a static table and became a living model we could analyze, compare, and extend over time.

Here’s what the income statement ultimately helps us answer:

How well does this business turn activity into profit?

But the income statement only tells part of the story.

It explains performance over time, but it doesn’t tell us what the business owns, what it owes, or how it’s financed.

That’s where the balance sheet comes in.

In the next lesson, we’ll shift from performance to position. We’ll look at assets, liabilities, and equity – and see how the balance sheet connects directly to the income statement you just built.

Think of it this way:

  • The income statement tells us how the business performed
  • The balance sheet tells us what the business looks like right now

Let’s move on and complete the picture.