My prediction for DDP vs Chimaev

Been a while I've watched it tho ... It was highly commented when I was a kid as the "most terrible movie ever". It's kinda idk based on the graphics but I've always disliked movies of serial/fictional killers. At least this one is off a fictional character... when it's about irl ones, I can't watch it. The original 1980 one that is about his mother, Pamela who killed multiple consolers was the most disturbing one to me tho ... For some reason when it's a woman many feel that way, like when the main danger is a kid or an old man/lady... It gives a more off-putting vibe curiously, I think because we subconsciously look at them as less threatening, which makes it more daunting too
 
But I prefer spiritual horror movies. The Others remains as one of my favourite ones. The timing I had watched this one made it more special too
 
It’s not magic, I use my yellow lens to sound like a nerd 🤓 and then just NumPy for random draws, pandas to hold the fighter stats, SciPy’s beta/poisson stuff for rates, and a little of a logistic head to turn feature deltas into win probabilities.

I can trim down to share the code here if you are REALLY INTERESTED, if not, then I won't waste my time writing the trim of the code lol...

... Anyways since it's fun and enjoyable, I will write a basics outline ...


-----


import numpy as np
import pandas as pd
from scipy.stats import beta, poisson
from sklearn.linear_model import LogisticRegression

rng = np.random.default_rng(42)




# --- toy data just to show structure ---
fighters = pd.DataFrame([
{"name": "F1", "slpm": 5.6, "sapm": 3.1, "td_acc": 0.38, "td_def": 0.78,
"sub_avg": 0.3, "str_acc": 0.52, "str_def": 0.60},
{"name": "F2", "slpm": 3.9, "sapm": 2.7, "td_acc": 0.42, "td_def": 0.72,
"sub_avg": 0.6, "str_acc": 0.48, "str_def": 0.55},
])

def sample_rate(p, n=200):
"""Sample a probability with uncertainty via Beta."""
# alpha/beta are crude: successes ~ p*n, failures ~(1-p)*n
a, b = max(p*n, 1), max((1-p)*n, 1)
return rng.beta(a, b)

def sim_fight(row1, row2, minutes=25):
# sample noisy versions of key rates
f1_acc = sample_rate(row1.str_acc)
f2_acc = sample_rate(row2.str_acc)
f1_td_a = sample_rate(row1.td_acc)
f2_td_d = sample_rate(row2.td_def)
# expected landed strikes using simple Poisson
f1_exp_str = rng.poisson(f1_acc * row1.slpm * minutes)
f2_exp_str = rng.poisson(f2_acc * row2.slpm * minutes)
# crude takedown math
f1_exp_td = rng.binomial(8, f1_td_a * (1 - row2.td_def))
f2_exp_td = rng.binomial(8, sample_rate(row2.td_acc) * (1 - row1.td_def))
# feature vector for a tiny logistic head
X = np.array([[f1_exp_str - f2_exp_str,
f1_exp_td - f2_exp_td]])
# weights picked by quick CV offline; hard-coded here
w = np.array([0.015, 0.20])
logit = X @ w
prob_f1 = 1 / (1 + np.exp(-logit))
return prob_f1[0]

def run_mc(f1, f2, n=10000):
row1 = fighters.loc[fighters.name == f1].squeeze()
row2 = fighters.loc[fighters.name == f2].squeeze()
probs = [sim_fight(row1, row2) for _ in range(n)]
return np.mean
(probs)

print(run_mc("F1", "F2", n=5000))


----

There are some basic comments so you know what each piece does more or less


It basically samples noisy strike/TD rates with Beta, then turns them into counts (Poisson/Binomial), feeds a tiny 2-feature logistic to spit a win prob. Swapping the actual UFCStats numbers and expanding features (knockdowns, control time, etc.) gives the gist of it....

If you're really interested, I can DM the full outline, but it's big... To sum up, data scrape —> clean —> feature engineering —> CV on historical fights... Showing the whole thing would be too big for a post unless I zip it but since I think you aren't that serious I will leave it at that ....

Credit where it's due, you actually wrote Python code to run simulations and posted it <lmao>

How about posting some of the results of these simulations then?

As someone who has never seen Python code before, it's bizarre. More of a scripting language than I expected, with no typed variables. And for example you're using these packages Numpty and PandaBear to create arrays and 2d arrays rather than just, you know, creating them ;)

Also you're multiplying one array with another array, as if they're Vectors. Just absolutely bizarre.
 
its actually unrealistic Khamzat wins. khamzat hasn't been tested in deep waters of late rounds often as when he has his cardio isn't ideal and his game isn't tailored to the stand up despite his skilled strikes and power.

DDP on the other hand, is and somehow keeps going even when he looks gassed. DDP as we know always looks big no matter whom he stands right next to. taking down DDP is a whole other thing compared to whomever Chimaev has faced. DDP is naturally smart enough to anticipate those early TD blitzes and it's obvious his team have been engineering a gameplay to bypass that and take Chimaev past his best 1-2 rounds, thereby the early ones.

predicting a Du Plessis win as well.
 
Credit where it's due, you actually wrote Python code to run simulations and posted it <lmao>

How about posting some of the results of these simulations then?

As someone who has never seen Python code before, it's bizarre. More of a scripting language than I expected, with no typed variables. And for example you're using these packages Numpty and PandaBear to create arrays and 2d arrays rather than just, you know, creating them ;)

Also you're multiplying one array with another array, as if they're Vectors. Just absolutely bizarre.
It looks weird at first cuz "plain" Python lists aren't for math, they're generic containers. NumPy (not "NumPty" lol) gives you real n-dimensional arrays under the hood in C, so you can treat them like vectors or matrices... That way you don't need to write 500 for-loops. Same thing with pandas (panda bear lol) for table-ish data... Think of an excel sheet but fast and programmable. It's dynamically typed sure but it's not something lawless. You can add type hints if you want like (x: np.ndarray) and tools like mypy will show if you mess up.... Point being, prototype fast, enforce types when it matters. And multiplying arrays is the whole point of vectorization — a * b is elementwise, a @ b is matrix multiply.... It's way cleaner than manual indexing. Yeah scripting language works on the surface but the "heavy lifting" is compiled. You get readable code up and speed down below... Once you understand the syntax it's actually way less bizarre than writing like, triple-nested loops just to sum two vectors.
 
It looks weird at first cuz "plain" Python lists aren't for math, they're generic containers. NumPy (not "NumPty" lol) gives you real n-dimensional arrays under the hood in C, so you can treat them like vectors or matrices... That way you don't need to write 500 for-loops. Same thing with pandas (panda bear lol) for table-ish data... Think of an excel sheet but fast and programmable. It's dynamically typed sure but it's not something lawless. You can add type hints if you want like (x: np.ndarray) and tools like mypy will show if you mess up.... Point being, prototype fast, enforce types when it matters. And multiplying arrays is the whole point of vectorization — a * b is elementwise, a @ b is matrix multiply.... It's way cleaner than manual indexing. Yeah scripting language works on the surface but the "heavy lifting" is compiled. You get readable code up and speed down below... Once you understand the syntax it's actually way less bizarre than writing like, triple-nested loops just to sum two vectors.

Well it might be cleaner than doing it manually, but is it faster? And it's no cleaner than actual vectors in C, which are clean and very fast. Arrays have boxing/unboxing. Compared to vectors which have direct data access, you're essentially doing 2 memory lookups.

For you this might be fine doing offline simulations etc, but for realtime applications speed is crucial.

For example there is a library in C# called Linq, that has some of the operators you've shown, but under the hood it's slow and generates a lot of garbage, so is far from ideal for real world use.

Have you tried benchmarking the a * b operator compared to manual loops/calculations?

Admittedly the code is certainly trim and clean with those kind of operators replacing loops, if it could compile to machine code that was just as efficient.

Untyped variables fucking suck though ;)
 
Last edited:
Been a while I've watched it tho ... It was highly commented when I was a kid as the "most terrible movie ever". It's kinda idk based on the graphics but I've always disliked movies of serial/fictional killers. At least this one is off a fictional character... when it's about irl ones, I can't watch it. The original 1980 one that is about his mother, Pamela who killed multiple consolers was the most disturbing one to me tho ... For some reason when it's a woman many feel that way, like when the main danger is a kid or an old man/lady... It gives a more off-putting vibe curiously, I think because we subconsciously look at them as less threatening, which makes it more daunting too
Fuck me, I liked a Luffy post. Not that I agree with it too much, but at least it has some merit.
 
I'd definitely have chose another username nowadays. Luffy was a random pick in 2017 since I couldn't think of whatever username as I'm terrible with coming up with new usernames lol. But since I'm known as Luffy by everyone here no way I'm changing that now even tho I wish haha
Apparently this guy is also Luffy

luffy-ride-it.gif
 
its actually unrealistic Khamzat wins. khamzat hasn't been tested in deep waters of late rounds often as when he has his cardio isn't ideal and his game isn't tailored to the stand up despite his skilled strikes and power.

DDP on the other hand, is and somehow keeps going even when he looks gassed. DDP as we know always looks big no matter whom he stands right next to. taking down DDP is a whole other thing compared to whomever Chimaev has faced. DDP is naturally smart enough to anticipate those early TD blitzes and it's obvious his team have been engineering a gameplay to bypass that and take Chimaev past his best 1-2 rounds, thereby the early ones.

predicting a Du Plessis win as well.
It is definitley not unrealistic for Khamzat to take him down and choke him in round 1, like he does to almost everyone he's fought.

It will never surprise me if he does that to ANYONE
 
This is the first time Khazmat has faced a real legit MW sized guy since who Gerald?

Leech = WW
Burns =LW/WW
Holland = not even top 15 at WW.
Usman = WW
Rob = MW/WW very small in comparison.

Hopefully he gets smashed but really don’t like either.
 
Lol I asked ChatGPT, none of the fanboys will like it:

🥊


Khamzat Chimaev vs. Dricus Du Plessis
5 Rounds – Main Event





🛎️ Round 1:​


4:55 – Chimaev sprints across the cage, instantly shoots for a double leg.
4:50 – Du Plessis defends well initially, frames off, but is dragged down against the cage.
4:30 – Khamzat works from half guard, throwing sharp elbows. Dricus absorbs them but is controlled.
4:00 – Du Plessis hip escapes and stands up, crowd roars. Chimaev immediately clinches.
3:30 – Du Plessis reverses position in the clinch and lands a few knees to the body.
3:00 – They separate. Dricus throws a wild overhand right—lands partially.
2:30 – Chimaev eats it and pressures forward. Lands a stiff jab and a low kick.
1:45 – Du Plessis catches Khamzat coming in with a short hook. Chimaev slows a bit.
1:00 – Chimaev shoots again, this time gets stuffed. Du Plessis lands an uppercut in the sprawl.
0:30 – Back on the feet. Both men trading awkward strikes. Dricus throws a spinning elbow, misses.
0:10 – Khamzat ends strong with a body lock and trip takedown.


📊 Round 1: 10-9 Chimaev – Control time, takedowns, early damage.




🛎️ Round 2:​


5:00 – Du Plessis starts to find his rhythm—pumping the jab and attacking with calf kicks.
4:30 – Chimaev’s pace slightly dips. Dricus lands a clean right hand.
4:00 – Chimaev shoots—gets stuffed again. Dricus sprawls and takes the back momentarily.
3:45 – Chimaev stands up quickly, but Dricus is landing knees to the body in the clinch.
3:00 – Du Plessis separates and lands a big overhand right! Chimaev wobbles!
2:45 – Chimaev backs up—possibly stunned. Dricus charges with looping hooks.
2:15 – Chimaev clinches to recover. Crowd is electric.
1:45 – Dricus with body shots inside. Chimaev pulls guard! Odd decision.
1:00 – Du Plessis stands over him, kicks the legs, then lets him up.
0:30 – Chimaev lands a desperation jab but looks labored.
0:10 – Du Plessis lands another clean combo to end the round.


📊 Round 2: 10-9 Du Plessis – More damage, denied takedowns, clean shots.




🛎️ Round 3:​


5:00 – Chimaev shows urgency. Comes forward throwing heat.
4:45 – Du Plessis throws a front kick to the body—Chimaev catches it and slams him!
4:15 – Chimaev on top in side control. Starts landing elbows.
3:30 – Du Plessis bucks hard, but Chimaev stays heavy. Moves to mount!
3:00 – Chimaev raining down punches! Dricus covers up but survives.
2:15 – Dricus scrambles to half guard. Blood from his nose.
1:30 – Chimaev hunting for an arm triangle, but Dricus defends.
1:00 – Dricus escapes to his knees and stands up! Crowd goes wild.
0:45 – Both swinging now—wild exchange, Chimaev eats a hook but lands a clean right.
0:10 – Big flurry by Chimaev ends the round strong.


📊 Round 3: 10-9 Chimaev – Dominant top control and a near finish.




🛎️ Round 4:​


5:00 – Du Plessis still fresh somehow. Opens with combinations and a jab.
4:30 – Chimaev looks slower. Shoots from distance—stuffed.
4:00 – Du Plessis punishes the failed shot with a knee to the body.
3:45 – Dricus lands a head kick partially blocked, then rips to the body.
3:15 – Chimaev tries to clinch but gets shrugged off.
2:45 – Du Plessis now walking him down. Lands a stiff jab and an uppercut!
2:00 – Chimaev backing up, breathing hard.
1:30 – Dricus fakes and lands a heavy right—Chimaev stumbles!
1:00 – Chimaev shoots again—deep shot—Du Plessis sprawls and sprawls hard.
0:45
– Dricus spins behind, lands punches to the side of the head.
0:10 – Dricus lets him up and waves him on. Brawl to end the round.


📊 Round 4: 10-9 Du Plessis – Better striking, stuffed takedowns, clean counters.




🛎️ Round 5 – Championship Round:​


5:00 – Both men exhausted. Chimaev knows he needs this round.
4:30 – Shoots immediately—deep double—gets it! Crowd roars.
4:00 – Chimaev in top position, grinding elbows. Du Plessis bleeding.
3:30 – Du Plessis trying to stand, but Chimaev is glued to him.
3:00 – Chimaev rides the back, softening up with punches.
2:30 – Du Plessis explodes and turns into him! Back to feet.
2:00 – Both men swinging sloppy bombs. No defense. Crowd on their feet.
1:30 – Dricus lands a brutal body shot. Chimaev backs off.
1:00 – Chimaev lands a left hook. Dricus answers with a jab.
0:30 – Chimaev shoots again—STUFFED.
0:15 – Du Plessis lands a final combo: jab-cross-hook!
0:00 – Horn sounds! Both collapse in exhaustion.


📊 Round 5: 10-9 Chimaev (barely) – Early takedown and control.




📋


48-47 Chimaev
48-47 Du Plessis
48-47… Dricus Du Plessis by Split Decision



🎉 Dricus Du Plessis retains/wins the Middleweight Championship
FOTY contender. Both men raised in respect.
 
Lol chat GPT predicting fights??? I wish I had mine yet but my plan ran off for a long time and I can't use it. I'd use it mainly to ask some college info details tho
 
It is definitley not unrealistic for Khamzat to take him down and choke him in round 1, like he does to almost everyone he's fought.

It will never surprise me if he does that to ANYONE
I need to make it clear I said for him to win. and the point about DDP's size and his odd centre of gravity is a valid point for he has come out to be a lot bigger than most anticipate and his size generally is a factor in his finest wins.

will it surprise me if Khamzat does what he says? absolutely not and with his new and more intelligent training regime he really seems in the form of his life.
 
  • Like
Reactions: HHJ
It’s not magic, I use my yellow lens to sound like a nerd 🤓 and then just NumPy for random draws, pandas to hold the fighter stats, SciPy’s beta/poisson stuff for rates, and a little of a logistic head to turn feature deltas into win probabilities.

I can trim down to share the code here if you are REALLY INTERESTED, if not, then I won't waste my time writing the trim of the code lol...

... Anyways since it's fun and enjoyable, I will write a basics outline ...


-----


import numpy as np
import pandas as pd
from scipy.stats import beta, poisson
from sklearn.linear_model import LogisticRegression

rng = np.random.default_rng(42)




# --- toy data just to show structure ---
fighters = pd.DataFrame([
{"name": "F1", "slpm": 5.6, "sapm": 3.1, "td_acc": 0.38, "td_def": 0.78,
"sub_avg": 0.3, "str_acc": 0.52, "str_def": 0.60},
{"name": "F2", "slpm": 3.9, "sapm": 2.7, "td_acc": 0.42, "td_def": 0.72,
"sub_avg": 0.6, "str_acc": 0.48, "str_def": 0.55},
])

def sample_rate(p, n=200):
"""Sample a probability with uncertainty via Beta."""
# alpha/beta are crude: successes ~ p*n, failures ~(1-p)*n
a, b = max(p*n, 1), max((1-p)*n, 1)
return rng.beta(a, b)

def sim_fight(row1, row2, minutes=25):
# sample noisy versions of key rates
f1_acc = sample_rate(row1.str_acc)
f2_acc = sample_rate(row2.str_acc)
f1_td_a = sample_rate(row1.td_acc)
f2_td_d = sample_rate(row2.td_def)
# expected landed strikes using simple Poisson
f1_exp_str = rng.poisson(f1_acc * row1.slpm * minutes)
f2_exp_str = rng.poisson(f2_acc * row2.slpm * minutes)
# crude takedown math
f1_exp_td = rng.binomial(8, f1_td_a * (1 - row2.td_def))
f2_exp_td = rng.binomial(8, sample_rate(row2.td_acc) * (1 - row1.td_def))
# feature vector for a tiny logistic head
X = np.array([[f1_exp_str - f2_exp_str,
f1_exp_td - f2_exp_td]])
# weights picked by quick CV offline; hard-coded here
w = np.array([0.015, 0.20])
logit = X @ w
prob_f1 = 1 / (1 + np.exp(-logit))
return prob_f1[0]

def run_mc(f1, f2, n=10000):
row1 = fighters.loc[fighters.name == f1].squeeze()
row2 = fighters.loc[fighters.name == f2].squeeze()
probs = [sim_fight(row1, row2) for _ in range(n)]
return np.mean
(probs)

print(run_mc("F1", "F2", n=5000))


----

There are some basic comments so you know what each piece does more or less


It basically samples noisy strike/TD rates with Beta, then turns them into counts (Poisson/Binomial), feeds a tiny 2-feature logistic to spit a win prob. Swapping the actual UFCStats numbers and expanding features (knockdowns, control time, etc.) gives the gist of it....

If you're really interested, I can DM the full outline, but it's big... To sum up, data scrape —> clean —> feature engineering —> CV on historical fights... Showing the whole thing would be too big for a post unless I zip it but since I think you aren't that serious I will leave it at that ....
Interesting. You're using a Monte Carlo sim, I'm actually impressed. You're truly an enigma on the forums.

Few methodological flaws: Fixed TDs at 8, your run_mc function doesn’t compute the mean due to a syntax error.

This is still an impressive model, especially home programmed to simulate a fight, using both statistical sampling and a logistic regression model. Instead of SPLM * STR ACC, reduce to SPLM directly.

Good job overall though.
 
Interesting. You're using a Monte Carlo sim, I'm actually impressed. You're truly an enigma on the forums.

Few methodological flaws: Fixed TDs at 8, your run_mc function doesn’t compute the mean due to a syntax error.

This is still an impressive model, especially home programmed to simulate a fight, using both statistical sampling and a logistic regression model. Instead of SPLM * STR ACC, reduce to SPLM directly.

Good job overall though.
Haha. I'm graduating in chemical engineering so that surely helps as I've seen that a lot by now.

The TD=8 was just a dumb placeholder so I could binomial something quickly without strictly adhering to every guy's attempt distro. Swapping to a Poisson/neg-bin fit off each other's actual attempts (or just sample from their empirical per-fight counts) so Khamzat isn't capped like he's shooting in a 3-rounder.

The run_mc mean "bug" is on me trimming for the post. In the complete one it's np.mean(probs) (or
np.asarray(probs).mean()), I probably messed a bracket when I typed.

On the SLpM * StrAcc: I multiplied to get a raw "landed per minute" signal in one feature, but yeah it's basically collinear with just using SLpM (since SLpM already gets accuracy in). I can drop the product, keep raw SLpM and then let the logistic weights figure it out or keep both and regularize harder. Not attached to it.

I also added control time deltas, knockdowns, and reversals, as separate features. The little 2-weight head was just to show the flow.

Thanks for the eyes, tightening up the code is always easier when ppl read the code ^_^
 
Last edited:
Imagine how much time OP spent crafting that post thinking someone might actually read it and/or care
 
Luffy you posted the code and good on you, proved you were sincere 👍

But you haven't posted arguably the most important thing - the average result of this simulation.
 
Back
Top