Python & Data Science
Deep Learning Under review

Neural Networks, Without the Calculus: What's Actually Happening Inside a Single Neuron

You’ve probably heard that neural networks are inspired by the brain. True, but misleading. The reality is simpler and more useful: a neuron is just a tiny decision-maker. It looks at evidence, weighs what matters, and makes a call. You do this every day. Let’s build one from scratch—no calculus required.

Will This Customer Buy? A Problem You Already Solve

Picture a visitor moving through an online store. Will they buy something right now?

That’s the problem facing Lina, a junior ML engineer at BookSight, an online bookstore. Her first project: build a model that predicts whether a visitor will buy a book based on their browsing session. The time-on-page and cart data she’s working with come straight from BookSight’s real session logs.

You have two pieces of evidence—how many minutes they’ve spent on the page, and how many books they’ve added to their cart. They don’t matter equally. Adding a book to the cart signals intent far more strongly than lingering on a page. So you’d want your prediction to weight the cart more heavily than the clock.

That’s what a neuron does. It’s a tiny judge that looks at multiple inputs, decides which ones matter more, and outputs a decision.

Start with the simplest version. A rule that checks one thing: has this person spent more than 5 minutes on the page? If yes, flag them as a likely buyer.

def simple_shopper_check(time_on_page):
    if time_on_page > 5:
        return "LIKELY BUYER"
    else:
        return "NOT YET"

# Let's test it
print(simple_shopper_check(8))  # Output: LIKELY BUYER
print(simple_shopper_check(3))  # Output: NOT YET
  • if time_on_page > 5: — A single threshold on one variable: if the visitor spent more than 5 minutes browsing, flag them as a likely buyer.
  • The function returns one of two string labels — there’s no weighting, no combination of inputs, no learning. It’s a pure “if this, then that” heuristic with exactly one knob (the cutoff) and exactly one input.

That works, but it ignores the cart entirely. A real neuron considers multiple inputs at once. Here’s the key insight: a neuron doesn’t just check whether something is above a threshold. It combines all inputs into a single number first, then checks that total against a threshold.

Think of it this way—the neuron adds up all the evidence, then decides based on the total.

Weights: The Volume Knobs of Data

Now let’s make the prediction smarter. We have two inputs: time on page and items in cart. But they shouldn’t be treated the same way.

Here’s what’s going on: we multiply each input by a number that tells us how much to care about it. That multiplier is a weight. Think of it as a volume knob for each input.

Give items in cart a weight of 3 and time on page a weight of 0.4, and each cart item becomes worth about 7.5 times more than each minute of browsing (3 divided by 0.4). The neuron “listens” more carefully to the cart than to the clock.

Here it is in code:

def weighted_purchase_predictor(time_on_page, items_in_cart):
    # These are our weights—how much we care about each input
    weight_time = 0.4
    weight_cart = 3

    # Multiply each input by its weight
    time_contribution = time_on_page * weight_time
    cart_contribution = items_in_cart * weight_cart

    # Add them up
    total = time_contribution + cart_contribution

    # Check if the total is above a threshold
    if total > 6:
        return "LIKELY BUYER"
    else:
        return "NOT YET"

# Let's test it
print(weighted_purchase_predictor(time_on_page=8, items_in_cart=2))  # Output: LIKELY BUYER
print(weighted_purchase_predictor(time_on_page=5, items_in_cart=0))  # Output: NOT YET
  • weight_time = 0.4, weight_cart = 3 — Each input gets its own multiplier. The cart weight is 7.5× larger than the time weight, encoding the intuition that adding a book to the cart matters far more than lingering on a page.
  • time_contribution = time_on_page * weight_time — Scale the time input down by its weight (0.4), so 8 minutes contributes only 3.2 to the total.
  • cart_contribution = items_in_cart * weight_cart — Scale the cart input up by its weight (3), so 2 items contribute 6.0 to the total.
  • total = time_contribution + cart_contribution — Sum both weighted contributions into one combined evidence score.
  • if total > 6: — Compare the combined score against a single threshold. This is the step that replaces the one-variable cutoff from simple_shopper_check with a multi-variable decision boundary.

Walking through the first example: time on page is 8, items in cart is 2.

  • Time contributes: 8 × 0.4 = 3.2
  • Cart contributes: 2 × 3 = 6.0
  • Total: 3.2 + 6.0 = 9.2

9.2 sits above our threshold of 6, so we flag them as a likely buyer. The cart had a bigger say even though “2” is a smaller number than “8”—its weight was just that much higher. That’s the whole point of weights: they let us tell the neuron which inputs matter more.

The Bias: Your Personal Grumpiness Factor

Here’s a problem with our predictor. What if someone has spent zero minutes on the page and has an empty cart? They just landed—give them a second. The total would be zero, and we’d say “NOT YET.”

Maybe you want a default setting, though. Your store could be running a big sale, casting a wide net for retargeting ads—flagging people as likely buyers even on modest signals. Or your ad budget is tight, and you only retarget visitors you’re already confident about.

That’s where the bias comes in. It’s a number we add to the weighted sum before checking the threshold. Think of it as the neuron’s default starting position.

A high bias makes the neuron eager to say yes—a generous store casting a wide net. A low or negative bias makes it cautious. It demands a lot of evidence before firing, like a store that only wants near-certain buyers.

def biased_purchase_predictor(time_on_page, items_in_cart, bias=1.5):
    # Weights
    weight_time = 0.4
    weight_cart = 3

    # Weighted sum
    total = (time_on_page * weight_time) + (items_in_cart * weight_cart) + bias

    # Check threshold
    if total > 6:
        return "LIKELY BUYER"
    else:
        return "NOT YET"

# Test with default bias
print(biased_purchase_predictor(time_on_page=4, items_in_cart=1))  # Output: LIKELY BUYER
print(biased_purchase_predictor(time_on_page=4, items_in_cart=1, bias=-4))  # Output: NOT YET
  • bias=1.5 (default argument) — The neuron starts every prediction with a +1.5 head start, making it “eager” to flag buyers even on weak signals.
  • total = (time_on_page * weight_time) + (items_in_cart * weight_cart) + bias — This is the complete weighted-sum-plus-bias formula: scale each input by its weight, add them together, then add the bias on top.
  • bias=-4 (second test call) — Overrides the default with a large negative value, shifting the neuron into “cautious” mode where it subtracts 4 from every score before deciding.
  • Same inputs (4, 1) in both calls, but the bias alone flips the output from “LIKELY BUYER” to “NOT YET.”

In the first call, the total is (4 × 0.4) + (1 × 3) + 1.5 = 1.6 + 3 + 1.5 = 6.1. That’s above 6, so we flag a likely buyer.

In the second call, the total is (4 × 0.4) + (1 × 3) - 4 = 1.6 + 3 - 4 = 0.6. That’s below 6, so it’s “not yet.” Same inputs, different bias, different output. The bias shifts how willing the store is to bet on this visitor.

Activation Functions: The Final Filter

Now here’s the tricky part—this is the hardest concept in the article. So far we’ve been checking if the total crosses a threshold, returning “LIKELY BUYER” or “NOT YET.” Binary. But we might want a more nuanced answer from the neuron.

Instead of “LIKELY BUYER” or “NOT YET,” what if it could say “I’m 94% confident this person will buy”? That’s far more useful, especially when many neurons work together.

To get there, we squash the raw number into a range between 0 and 1. That’s what an activation function does. It takes any number—positive, negative, huge, tiny—and compresses it into a probability.

The most famous one is the Sigmoid. Think of a light switch that isn’t all-or-nothing but a dimmer. Push more current through, and the light gets brighter. It never drops below 0% or climbs past 100%. The Sigmoid does the same thing with numbers.

Let’s implement it:

import math

def sigmoid(x):
    # This formula squashes any number into a value between 0 and 1
    return 1 / (1 + math.exp(-x))

# Let's see what happens with different inputs
print(sigmoid(0))      # Output: 0.5 (neutral)
print(sigmoid(5))      # Output: 0.9933 (very confident yes)
print(sigmoid(-5))     # Output: 0.0067 (very confident no)
print(sigmoid(100))    # Output: 1.0 (extremely confident yes)
  • 1 / (1 + math.exp(-x)) — The sigmoid formula. math.exp(-x) computes e raised to the power of negative x.
  • When x is large and positive (e.g. 5): exp(-5) is tiny (≈ 0.0067), so the denominator is ≈ 1.0067, and the output is ≈ 0.9933 — very close to 1.
  • When x is large and negative (e.g. -5): exp(5) is huge (≈ 148.4), so the denominator is ≈ 149.4, and the output is ≈ 0.0067 — very close to 0.
  • When x is exactly 0: exp(0) is 1, so the output is 1 / (1 + 1) = 0.5 — perfectly neutral.
  • sigmoid(100) — Even an extreme input like 100 saturates to 1.0 (floating-point rounding), illustrating the “dimmer” ceiling: the output can never exceed 1.

Notice what happens. Pass in 0, and you get 0.5—right in the middle. Pass in a big positive number like 5, and you get 0.9933, very close to 1. Pass in a big negative number like -5, and you get 0.0067, very close to 0.

The Sigmoid acts as a translator. It takes the raw sum—which could be anything—and converts it into a probability between 0 and 1. The bigger the sum, the closer to 1. The smaller, the closer to 0.

Let’s See What Happens: Putting the Neuron Together

Now we have all the pieces. We can combine them into a single Neuron class that takes inputs, multiplies by weights, adds the bias, and squashes the result through the Sigmoid.

import math

class Neuron:
    def __init__(self, weight_time, weight_cart, bias):
        self.weight_time = weight_time
        self.weight_cart = weight_cart
        self.bias = bias

    def sigmoid(self, x):
        # Squash any number into 0 to 1
        return 1 / (1 + math.exp(-x))

    def forward(self, time_on_page, items_in_cart):
        # Step 1: Multiply inputs by weights
        weighted_sum = (time_on_page * self.weight_time) + (items_in_cart * self.weight_cart)

        # Step 2: Add bias
        with_bias = weighted_sum + self.bias

        # Step 3: Apply activation function
        output = self.sigmoid(with_bias)

        return output

# Create a neuron
purchase_neuron = Neuron(weight_time=0.4, weight_cart=3, bias=-3.5)

# Test it on three scenarios
print("Engaged shopper (browsed + added to cart):", purchase_neuron.forward(time_on_page=8, items_in_cart=1))   # Should be high
print("Quick bouncer (barely looked, empty cart):", purchase_neuron.forward(time_on_page=1, items_in_cart=0))   # Should be low
print("Window shopper (long browse, empty cart):", purchase_neuron.forward(time_on_page=10, items_in_cart=0))   # Should be uncertain
  • __init__(self, weight_time, weight_cart, bias) — The constructor stores the neuron’s three personality settings as instance attributes: two weights (how much each input matters) and one bias (the neuron’s default eagerness).
  • sigmoid(self, x) — The same squashing function from the previous section, now bundled inside the neuron as a method so it’s always available.
  • forward(self, time_on_page, items_in_cart) — The full prediction pipeline in three steps:
    • Step 1: Multiply each input by its weight and sum them → weighted_sum.
    • Step 2: Add the bias → with_bias.
    • Step 3: Squeeze through sigmoid → a probability between 0 and 1.
  • purchase_neuron = Neuron(weight_time=0.4, weight_cart=3, bias=-3.5) — Lina creates one neuron with her chosen weights and a slightly cautious (negative) bias.
  • The three test calls cover the spectrum: a strong buyer signal, a weak one, and an ambiguous one — the outputs (≈0.94, ≈0.04, ≈0.62) show the neuron returning calibrated confidences rather than binary labels.

So what do these numbers tell us? Running the code produces outputs like 0.94, 0.04, and 0.62.

  • 0.94 means the neuron is 94% confident this visitor will buy. They browsed for a while and added something to their cart—strong evidence on both fronts.
  • 0.04 means the neuron is only 4% confident. They barely looked and never touched the cart. Not a buyer, at least not today.
  • 0.62 means the neuron is 62% confident—genuinely uncertain. This visitor spent a long time browsing but never added anything to their cart. That’s the classic “window shopper” pattern: real interest, but no commitment signal yet. The neuron correctly reads this as ambiguous rather than confidently yes or no.

These aren’t yes/no answers. They’re probabilities. The neuron tells you how confident it is — which is more useful than a binary switch.

The weighted sum (pre-activation)

z=w1x1+w2x2+bz = w_1 x_1 + w_2 x_2 + b

Each input xix_i is scaled by its weight wiw_i, the results are summed, and the bias bb is added. This produces a single raw score zz.

The sigmoid activation (post-activation)

σ(z)=11+ez\sigma(z) = \frac{1}{1 + e^{-z}}

The raw score zz is squashed into a probability between 0 and 1.

Plain EnglishStatistical symbolPython equivalent
Time on page (input 1)x1x_1time_on_page
Books in cart (input 2)x2x_2items_in_cart
Weight for time on pagew1w_1weight_time
Weight for books in cartw2w_2weight_cart
Bias (default offset)bbbias
Weighted sum (raw score)zzweighted_sum + bias
Final probability outputσ(z)\sigma(z)self.sigmoid(with_bias)

Hand-written threshold rule vs. learned weighted-sum model

The simple_shopper_check approach — Pick one variable, set one cutoff by hand, and ship it. It’s transparent, trivially easy to deploy, and requires zero training data. But it only looks at one input at a time: the 5-minute threshold completely ignores whether the visitor put a book in their cart. If you want to consider a second signal, you have to write a new rule from scratch—and a third signal means yet another rewrite.

The weighted-sum neuron — Multiply every input by its own weight, add a bias, and squash the result through an activation function. The big leap isn’t the extra math; it’s that the weights and bias don’t have to be hand-typed. A learning algorithm can discover them from historical data, automatically finding the right balance between “time on page matters a little” and “cart items matter a lot” without Lina guessing the exact ratio.

Why the learned version generalizes better:

  • Multiple inputs at once: The weighted sum combines all evidence into one score, so the neuron can catch a visitor who browsed briefly but added two books — a pattern the single-variable threshold would miss entirely.
  • Automatic tuning: If BookSight adds a new signal (say, “number of reviews read”), the neuron just gains another weight; the rule-based approach needs a brand-new hand-written condition.
  • Captures interactions you didn’t think of: A learned model can discover that time-on-page matters more when the cart is empty than when it’s full — a cross-input pattern no simple threshold can express.

When to reach for the hand-written rule: Quick prototypes, strong domain certainty, and very few inputs. Once you have more than two or three signals — or you want the model to improve as data accumulates — the learned weighted-sum wins.

Wait, How Does It Learn? (A Sneak Peek)

Here’s the question you’re probably asking: we just made up the weights and bias. We set weight_time to 0.4 and weight_cart to 3 because we guessed. How does the neuron actually learn the right values?

That’s what makes this interesting. Right now, our neuron is a fixed calculator. A learning neuron works differently. It starts with random weights, makes predictions, checks whether those predictions are right, and nudges the weights toward a better answer.

Think of it like tuning a radio. You start with static. Then you turn the dial slowly, listening for the signal to come through clearer. Each tiny turn is a guess about which direction to go. Neural networks do the same: they adjust weights in small steps, checking after each step whether predictions improved.

In Part 2, we’ll get into exactly how that works. We’ll see how the neuron realizes it’s wrong and corrects course. Then we’ll walk through the algorithm that handles the weight-tweaking and build a neuron that actually learns from data.

For now, remember this: a neuron is a decision-maker with three main parts. Inputs. Weights, which act as volume knobs. A bias, which is its personality. And an activation function, a filter that turns the raw answer into a probability. No calculus. No brain metaphors. Just a simple machine that combines evidence and makes a call.

You now understand what’s inside a single neuron. In Part 2, we’ll see how neurons learn. Lina hand-picked the weights in this prototype herself, but a real model needs to learn them from data—setting up everything that comes next.

Check Your Understanding

Questions below move from simple recall up to open-ended design, roughly following Bloom’s Taxonomy.

Remember What are the three main components of a neuron described in this article, and what does each one do?

Understand In your own words, explain why items_in_cart was given a much larger weight (3) than time_on_page (0.4). What would it mean, in terms of customer behavior, if you set those two weights equal instead?

Apply Using the weighted formula from this article (weight_time = 0.4, weight_cart = 3) with a bias of 2 and a threshold of 6, would a visitor with time_on_page = 3 and items_in_cart = 1 be flagged as a LIKELY BUYER? Show your work.

Analyze The “window shopper” scenario (10 minutes on the page, empty cart) produced a moderate confidence score of 0.62—neither a confident yes nor a confident no. Walk through why the math produces a middling number here instead of a low one, given that the cart is empty.

Evaluate The article’s weights bake in the assumption that adding an item to a cart is always a stronger buying signal than time spent browsing. Critique that assumption: describe a realistic shopper behavior where it would lead the neuron to the wrong conclusion.

Create Design one additional input signal a real online store could plausibly measure (something other than time on page or items in cart), and propose a weight for it relative to weight_cart = 3. Justify your choice using the same “how much more does this matter” reasoning the article used to justify weight_cart over weight_time.


References & Further reading

  • McCulloch, W. S., & Pitts, W. (1943). “A Logical Calculus of the Ideas Immanent in Nervous Activity.” Bulletin of Mathematical Biophysics, 5, 115–133. — The original paper that introduced the mathematical model of a neuron.
  • Perceptron (Wikipedia) — A plain-English overview of the perceptron, the historical predecessor to the modern artificial neuron and the simplest learnable weighted-sum classifier.

Apply What You Learned is for Supporter and Insider subscribers.

Subscribe to unlock the exercises on this post.

See plans

Looking for something else?

Search every article by title, summary or topic.