Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: math

  • Critical Math

    Critical Math

    In this downtime of little new TV and a need to distract once in a while, I proposed we watch all of S1 Critical Role (which I really only half ass watched until Percy died and came back). So on Thursday at late Saturday nights we watch old-school Critical Role. Sometimes we sneak in another episode but basically we’ve been grinding through.

    The other day we got to Omens and had to pause while we argued about math.

    We’d hit a point where Matthew Mercer was rolling for an absent Ashley Johnson. She was the cleric and he rolled her healing spell which restores people for 4D8+5 hit points. Matt got a total of 20.

    “Oh,” says my wife, disappointed. “Below average.”

    I mused aloud, “I know the average of 2D6 is 7, but I forget the math.”

    This led to an old argument about the law of averages and statistics, which is to say there is a one in eight chance of rolling an eight (8) on any given roll of a 1D8. No matter how many times people say the dice are good or bad, you have the same chance every time. Flipping a coin 100 times will give you roughly 50 heads and 50 tails. Over time, the wiggliness of Xeno’s Paradox will keep the numbers from a true 50-50,but the point remains you will always have a 50% chance of tossing a heads or a tails.

    Related to this, though, are the odds of two heads in a row. The problem with the math is a combination of fairness and a concept known as “the Gambler’s Fallacy.” It’s also called “the Monte Carlo Fallacy” because of the time it happened at Monte Carlo. See if the odds of a heads is 1 in 2, then the odds of heads twice in a row is 1 in 4. Three in a row is 1 in 8, because you double it on down. Four in a row is 1/16, and five is 1/32, and this goes on.

    And this confuses people because even if the odds of flipping a coin to heads 20 times in a row is 1 in 1,048,576, this does not change that the odds of flipping heads for #21 is both one in 2 and 1 in 2,097,152. To bake your noodle a little more, if you’ve flipped a coin 20 times for heads, the odds of flipping the 21st to be tails is … also 2,097,152.

    This is because we’re looking at two different things here. The probability of a heads or a tails will always and forever be 50%. Period. The odds of rolling a Natural 20 on 1D20 will always be 1/20th (5% for those wondering). Those will never change. This is Bayes’ theorem in action.

    We all get screwed up about this because we believe that fairness (i.e. the permanent 50%-ness of the toss) means that previous failures (or successes) will change the probability of the next toss. It won’t.

    Let’s say we’re rolling 1D20 and it’s a fair roller. Our goal is to get a 20 and the probability of that is 5%.

    But what about the odds of rolling a 20 at least once in 20 rolls? Well that’s 64%.

    There’s a 95% chance of not rolling a 20 (or any other given number) but again that doesn’t change. Every roll you have a 95% chance of not rolling a 20 and a 5% chance of rolling a 1 or a 20 (unless you’re Wil Wheaton or Taliesin Jaffe). But this makes us ask another question. If there’s a 64% chance of a critical success (i.e. a 20) in 20 rolls of 1D20, does that change if my first roll is a non-20?

    Kind of. It’s 62%.

    Yes, it went down. Why? Because you have fewer chances to win! So the odds of a critical drop every time you roll a non-critical. And frankly this explains half of Wil Wheaton — he’s rolled so many non-critical, the odds are astronomical for him to actually roll one. On the other hand, his capacity for rolling 1s makes him the Joe DiMaggio of Failure for D&D. Sorry, Wil.

    This is exactly the same kind of argument my father made back in 2016 (see Hot Hands And Playoffs from 2016). And I came to the same conclusion. Wheaton and Jaffe are what we call outliers.

    An Aside: For anyone who’s confused, Wil Wheaton (yes Wesley Crusher from Star Trek, also a great writer, a gamer, and a generally amazing human) plays D&D. He has an incredibly capacity to fail his rolls, to the point that a term was coined: Wheatoning (see also the math on Wheatoning). Opposite this is Taliesin Jaffe (an actor, director, voice actor, an all around cool guy) who has a bizarre talent at successes. At least, he did as Percy in Series 1 of Critical Role, with a dice called “The Golden Snitch.” This die was later stolen. Long story. Taliesin still rolls crazy high, so most Critical Role fans see them as the opposite ends of the spectrum.

    Whew. Okay that was a lot of math to tell you that while people want to think “If I roll a non-20 10 times in a row, the odds go UP for my next roll to be a 20!” and the truth is that the odds go down. There is no universal mathematical law of fairness, just of averages.

    Back to the Critical Role episode in question. So Mercer rolled a 20 for 4D8+5. That’s pretty normal for Ashley Johnson (she has a tendency to roll below average, but not to the point that you think she’s cursed like poor Wheaton). At the time, I couldn’t remember the math, but I remembered the experiment, which was that the majority of the faces on a d6 add up to 7.

    You may be thinking “Mika, there are only three: 6 + 1, 5 + 2, 4 + 3.” and that’s true but it’s actually 6 because the inverses are true. But ask yourself how many possibilities are there with 2D6? There are 11. (2 through 12, you can’t roll a 1 on two dice). And 3 of the 11 are a seven so that’s 27% odds of a 7?

    No. It’s 16%. Again we’re talking about frequency versus probability. There are 11 possible outcomes, but there are 36 possible variants. You always have six chances to get a 7, one to get a 2, and one to get a 12. This means that to get the probability (i.e. the odds) of rolling a 7, you have to take the frequency of getting a 7 (again, that’s 6) and divide it by the total number of frequencies (36). And 6/36 is 16.67%.

    Here’s a table to help:

    Dice RollFrequencyProbability
    212.8%
    325.6%
    438.3%
    5411.1%
    6513.9%
    7616.7%
    8513.9%
    9411.1%
    1038.3%
    1125.6%
    1212.8%

    It’s annoying to think that you always have two sets of probabilities, but if it helps we’re talking about likelihood versus probability. The likelihood of rolling a 7 on 2D6 is 16.8% (rounding up). The probability is 1 in 11. With one die, it’s always a flat sameness (likelihood of rolling a 20 is 1 in 20, so is the probability).

    We’ve gone around a bit. I know. Here’s the fun stuff. Before arguing math stuff, my wife says “Oh just add up the opposite sides of a die.”

    In my defence I never looked.

    A quick check on this and we learned some really hilarious factoids:

    1. She’s right (12+1 = 13 and 2d12 is in fact average 13).
    2. This works because the math is “highest number on the die plus the lowest number equals the average of two dice of the same face.”
    3. On standard dice the 1 and the high number are opposite (6 and 1, 8 and 1, etc).
    4. All the opposite sides add up to the average.
    5. On a D10 this breaks because the 0 is opposite a 9, which is technically highest and lowest, but they add up to 9 (or 19, D10s are weird). The average is 11.
    6. One of my D8s is misprinted and has 8 opposite 7. It was the first one we checked..

    Of course the first die we checked happened to be the misprint. The purple die in the photo below is buck wild and all wrong.

    Two eight-sided dice. The off-white one (properly) shows a 5 below the 8, the purple shows a 3.

    This is the only die in that set (in fact, of all our regularly used dice) that has been misprinted. And while technically the change in weight (different numbers are different sizes and have a different amount of paint on each bit) means the die rolls wrong, it’s not statically significant for me to worry much. Dice have a standard set so that numbers can be trusted. Also it makes math easier for people. The average of 2D20 is *drumroll* 21.

    Let’s go back to Ashley Johnson. Mercer rolled a 20 on 4D8+5. Is that below average? Oh yes it is.

    The average of 4D8 is 18 because 2D8 = 8 + 1 – 9 times 2 is 18. Add 5 and the new average becomes 23. a 20 is 3 points under. But at least you can’t roll under a 9!

    Bonus Section

    The wonderful thing about Math is you can see parallels. Once you know 2D6 is 7, you can start to jump. 4D16 is 14 and so on. But… what does ‘6 + 1’ mean. How would you get there?

    Me I look for patterns. 6 is the maximum of one die. One is one-half the number of dice rolled. Then it stands to reason that 4D6 is going to be 6 plus something with 4, right? 6 plus 8 is 14, so is that our pattern? No because going back one means “6 plus 2 is 8” and that isn’t seven. So how did we get the one? One is one half the number of dice…

    DiceAverageMax + DiceMax + 1/2 Dice
    2D676 + 2 = 86 + 1 = 7
    4D6146 + 8 = 146 + 2 = 8
    6D6216 + 6 = 186 + 3 = 9

    None of those are right but … Do you see the patterns?

    First the average starts at 7 and you add 7 for every 2 dice you add.

    We need to add something to a six, but it has to factor in with the number of dice. So how do we get to that one again? We know that the only way to make a one out of the first example (2D6) is to divide the dice by 2. For 2D6 we’re adding 2, which means what plus 2 gets to 14? A 12. And what is 12 divided by 6? A 2…

    Hang on then. We have a possible pattern!

    ( maximum score of one die * half the dice rolled ) + ( half number of dice rolled )

    DiceAverage( Max * 1/2 Dice ) + ( 1/2 Dice)
    2D67( 6 * 1 ) + ( 2 / 2 ) = 6 + 1 = 7
    4D614( 6 * 2 ) + ( 4 / 2 ) = 12 + 2 = 14
    6D621( 6 * 3 ) + ( 6 / 2 ) = 18 + 3 = 21
    8D628( 6 * 4 ) + ( 8 / 2 ) = 24 + 4 = 28
    10D635( 6 * 5 ) + ( 10 / 2 ) = 30 + 5 = 35

    Bingo baby! We have our pattern! But does this work for odd numbers? It must for the formula to be correct…

    DiceAverageForumula
    1D67( 6 * .5 ) + ( 1 / 2 )
    3D610.5( 6 * 1.5 ) + ( 3 / 2 )
    5D617.5( 6 * 2.5 ) + ( 5 / 2 )
    7D624.5( 6 * 3.5 ) + ( 7 / 2 )
    9D631.5( 6 * 4.5 ) + ( 9 / 2 )

    Yep, the math keeps working!

    And this, friends, is how you reverse engineer a formula.

  • It’s Just Math: WP-CLI Edition

    It’s Just Math: WP-CLI Edition

    Remember how I talked about doing math on a post when it was saved?

    Well what if I wanted to run that at another time? Like what if I knew I needed to update one show and I didn’t want to go in and save the post?

    I can to this with WP-CLI:

    WP CLI Magic

    class WP_CLI_MySite_Commands extends WP_CLI_Command {
    	/**
    	 * Re-run calculations for specific post content.
    	 * 
    	 * ## EXAMPLES
    	 * 
    	 *		wp mysite calc actor ID
    	 *		wp mysite calc show ID
    	 *
    	*/
    	
    	function calc( $args , $assoc_args ) {
    
    		// Valid things to calculate:
    		$valid_calcs = array( 'actor', 'show' );
    		
    		// Defaults
    		$format = ( isset( $assoc_args['format'] ) )? $assoc_args['format'] : 'table';
    
    		// Check for valid arguments and post types
    		if ( empty( $args ) || !in_array( $args[0], $valid_calcs ) ) {
    			WP_CLI::error( 'You must provide a valid type of calculation to run: ' . implode( ', ', $valid_calcs ) );
    		}
    
    		// Check for valid IDs
    		if( empty( $args[1] ) || !is_numeric( $args[1] ) ) {
    			WP_CLI::error( 'You must provide a valid post ID to calculate.' );
    		}
    
    		// Set the post IDs:
    		$post_calc = sanitize_text_field( $args[0] );
    		$post_id   = (int)$args[1];
    
    		// Last sanitity check: Is the post ID a member of THIS post type...
    		if ( get_post_type( $post_id ) !== 'post_type_' . $post_calc . 's' ) {
    			WP_CLI::error( 'You can only calculate ' . $post_type . 's on ' . $post_type . ' pages.' );
    		}
    
    		// Do the thing!
    		// i.e. run the calculations
    		switch( $post_calc ) {
    			case 'show':
    				// Rerun show calculations
    				MySite_Show_Calculate::do_the_math( $post_id );
    				$score = 'Score: ' . get_post_meta( $post_id, 'shows_the_score', true );
    				break;
    			case 'actor':
    				// Recount characters and flag queerness
    				MySite_Actor_Calculate::do_the_math( $post_id );
    				$queer = ( get_post_meta( $post_id, 'actors_queer', true ) )? 'Yes' : 'No';
    				$chars = get_post_meta( $post_id, 'actors_char_count', true );
    				$deads = get_post_meta( $post_id, 'actors_dead_count', true );
    				$score = ': Is Queer (' . $queer . ') Chars (' . $chars . ') Dead (' . $deads . ')';
    				break;
    		}
    
    		WP_CLI::success( 'Calculations run for ' . get_the_title( $post_id ) . $score );
    	}
    }
    

    What the What?

    The one for shows is a lot simpler. I literally call that do_the_math() function with the post ID and I get back a number. Then I output the number and I’m done. If I wanted it to run for all shows, I could use WP-CLI to spit out a list of all the IDs and then pass them to the command one at a time. Or I could write one that does ‘all’ posts. Which I may

    But the point is that I now can type wp mysite calc show 1234 and if post ID 1234 is a show, it’ll run.

  • Linear Regressions in PHP

    Linear Regressions in PHP

    Sometimes math exists to give me a headache.

    In calculating the deaths of queer females per year, my wife wondered what the trend was, other than “Holy sweat socks, it’s going up!” That’s called a ‘trendline’ which is really just a linear regression. I knew I needed a simple linear regression model and I knew what the formula was. Multiple the slope by the X axis value, and add the intercept (which is often a negative number), and you will calculate the points needed.

    Using Google Docs to generate a trend line is easy. Enter the data and tell it to make a trend line. Using PHP to do this is a bit messier. I use Chart.js to generate my stats into pretty graphs, and while it gives me a lot of flexibility, it does not make the math easy.

    I have an array of data for the years and the number of death per year. That’s the easy stuff. As of version 2.0 of Chart.js, you can stack charts, which lets me run two lines on top of each other like this:

    var myChart = new Chart(ctx, {
        type: 'bar',
        data: {
            labels: ['Item 1', 'Item 2', 'Item 3'],
            datasets: [
                {
                    type: 'line',
                    label: 'Line Number One',
                    data: [10, 20, 30],
                },
                {
                    type: 'line',
                    label: 'Line Number Two',
                    data: [30, 20, 10],
                }
            ]
        }
    });
    

    But. Having the data doesn’t mean I know how to properly generate the trend. What I needed was the most basic formula solved: y = x(slope) + intercept and little more. Generating the slope an intercept are the annoying part.

    For example, slope is (NΣXY - (ΣX)(ΣY)) / (NΣX2 - (ΣX)2) where,

    • x and y are the variables.
    • b = The slope of the regression line
    • a = The intercept point of the regression line and the y axis.
    • N = Number of values or elements
    • X = First Score
    • Y = Second Score
    • ΣXY = Sum of the product of first and Second Scores
    • ΣX = Sum of First Scores
    • ΣY = Sum of Second Scores
    • ΣX2 = Sum of square First Scores

    If that made your head hurt, here’s the PHP to calculate it (thanks to Richard Thome ):

    	function linear_regression( $x, $y ) {
    
    		$n     = count($x);     // number of items in the array
    		$x_sum = array_sum($x); // sum of all X values
    		$y_sum = array_sum($y); // sum of all Y values
    
    		$xx_sum = 0;
    		$xy_sum = 0;
    
    		for($i = 0; $i < $n; $i++) {
    			$xy_sum += ( $x[$i]*$y[$i] );
    			$xx_sum += ( $x[$i]*$x[$i] );
    		}
    
    		// Slope
    		$slope = ( ( $n * $xy_sum ) - ( $x_sum * $y_sum ) ) / ( ( $n * $xx_sum ) - ( $x_sum * $x_sum ) );
    
    		// calculate intercept
    		$intercept = ( $y_sum - ( $slope * $x_sum ) ) / $n;
    
    		return array( 
    			'slope'     => $slope,
    			'intercept' => $intercept,
    		);
    	}
    

    That spits out an array with two numbers, which I can plunk into my much more simple equation and, in this case, echo out the data point for each item:

    foreach ( $array as $item ) {
         $number = ( $trendarray['slope'] * $item['name'] ) + $trendarray['intercept'];
         $number = ( $number <= 0 )? 0 : $number;
         echo '"'.$number.'", ';
    }
    

    And yes. This works.

    Trendlines and Death

  • Hot Hands And Playoffs

    Hot Hands And Playoffs

    Today I’m wandering off topic into a world of baseball and statistics.

    My family have been Cleveland Indians fans since they came to the United States and settled in the city. My grandmother was an accountant, my father a mathematician, and I a web developer who works on software used by 26% of the Internet. Give or take. I’m also a third (and probably final) generation Clevelander. Yes, I root for my home team.

    October of 2016 marked the first time since 2007 that Cleveland was in the American League Championship Series (ALCS). In the intervening years, my family had all migrated to iPhones and iMessage, allowing us to converse in real time across two continents, two countries, four time-zones, and five cities.

    My father, the mathematician and risk analyst, kept a close watch on Nate Silver’s FiveThirtyEight project, especially the MLB Predictions, as Mr. Silver has been quite spot on for things for a while, understanding the implications of probability and chance.

    On October 18th, FiveThirtyEight gave Cleveland a 53% chance of winning the ALCS game 4, a 94% chance of making the World Series, and a 38% chance of winning it all for the first time since 1948. The time Cleveland won before that? 1920. Not quite Cubs level of history, but it’s been a long enough time than my grandmother Taffy never got to see them win a third time (she was born July 7, 1920).

    The game on the 17th was nothing short of incredible. The starting pitcher was yanked after 2 outs because his cut pinky was dripping blood. There are, you see, a bevy of incredible rules about what pitchers can and cannot wear. More than the normal player. And we’re talking about a sport than demands all players use a glove that has colors only within a PANTONE® color set lighter than the current 14-series. These guys are nuts. And one of the rules is no bandages on the pitchers’ hands.

    a pitcher’s person cannot include any unessential or distracting thing (including jewelry, adhesive tape, or a batting glove), especially on his arm, wrist, hand, or fingers.

    Bauer’s 11 stitches in his pinky split and was incredibly nasty, so he was replaced. Cleveland used seven pitchers, pretty much their entire relief bullpen, to get through the game. My family began to argue the intelligence of the move. Instead of using the rookie Merritt to start game 4, possible win-it-all game, Manager Terry Francona decided to start his ‘ace,’ Kluber.

    To understand this, you have to start with the odd fact that Cleveland is down three of their best pitchers to injuries. This is including Drone Boy Bauer. Such a situation is rare for the playoffs, if not unheard of. That means they are more reliant than ever on their bullpen, so using every single pitcher possible on Monday meant they would all be a little tired on Tuesday. And Kluber would be starting 3 days rest when a pitcher normally gets 4 or 5.

    Clearly Francona was banking on the team not needing to use the bullpen much on Game 4, but why would he make that decision knowing that the odds of winning on Tuesday were insanely low. As my dad said:

    Winning 7 games straight is an outlier. They won 6 in a row twice, of course the 14 streak, 4 games three times. I’m betting they will lose the next two in Toronto.

    Then he started emailing us all homework.

    Before we get to the math, let’s look at the baseball logic. The reason you would play Bauer is that the odds are Cleveland will lose on the 18th, and a good manager would know that and bet on it, like my father. Teams winning 7 games in a row is crazy. It’s rare. It’s risky. By playing Kluber, an experienced pitcher, you solve two problems. First, Merritt is a rookie. Him losing will have a deep psychological impact on the young guy. Kluber can take a hit and keep going. Second, it means if Cleveland does win, Kluber will be well rested for the World Series. If Game 4 is lost, Merritt will pitch the safer Game 5.

    The psychology of math is exactly why no one would discount the Cleveland Indians winning seven games in a row in the post season, however.

    […] what Terry is seeing is momentum, the intangible. You gotta measure the odds with numbers, but making good decisions goes beyond the odds … beyond just the odds. Like CoCo’s diving catch.

    This is where the homework comes into play. Nine papers about hot streaks later, I came to the conclusion I had always felt had to be true. There is no such thing as a winning streak. They are nothing more than standard deviations from the mean. Models of the math have told us that there is only one event in baseball that has happened outside of the frequency of said models. Everything, the longest runs of losses and wins, are exactly as they should be and happen as often as they ought.

    Except for one: Joe DiMaggio. Joltin’ Joe’s 56–game hitting streak in 1941 doesn’t make any sense. As we read in Streak of Streaks by Jay Gould, in order to make it mathematically probably to have a run of 50 games with a hit, we should have had four batters with a lifetime average of .400, and 52 with .350 or higher over 1000 games. Instead, three players have achieved a batting average over .350 and not one has managed .400 lifetime.

    You’re thinking “But Ty Cobb!” right now, and guess what? His lifetime is .367, followed by Hornsby at .358, and Shoeless Joe Jackson brings up the rear at .356 for his short career.

    DiMaggio’s streak does not make sense.

    Most MLB records we consider to be unbreakable are only that way due to changes in the way the game is played. Pitchers no longer play complete games on the regular, nor do they start 60+ games a season. The weirdness of DiMaggio is that his numbers are off the charts for that year, and actually the entirety of MLB history.

    The Hot Hand: A New Approach to an Old “Fallacy”. Notice the quotes? The theory behind the Sloan paper is that the Hot Hand (or streak) is a fallacy because we’ve always been working under bad assumptions. To whit:

    However, prior research hinges on the assumption that player shot selection is random, independent of player-perceived hot or coldness. Said differently, it assumes that players will take the same types of shots, with the same level of defensive coverage, regardless of whether they have just made or missed three shots in a row. We find this assumption difficult to believe – if players have been shooting well, it seems logical that they would begin to attempt more difficult shots and opposing defenses would begin to cover them more tightly. This would potentially counteract the Hot Hand effect.

    To make this more obvious to the conversation at hand, basketball is not baseball and men are not potatoes. Baseball is a rarity in sports. The defense has control of the ball and, barring injury, everyone who plays will have an at-bat (designated hitter rules aside). Basketball has no promise that everyone who plays will have a chance to shoot a basket, or even touch a ball. Baseball hitting streaks come down to one person versus a hundred. The batter versus every pitcher they face. Provided they’re not walked, the batter remains in control of their destiny.

    All of this is quite fanciful. There are hundreds of articles, like Phil Birnbaum’s quest for evidence of the Hot Hand effect and Tangotiger’s Sabremetric blog on the impact of the Zone on streaks. The best we can say is ‘Streaks exist, but generally they do so within the expected norm of percentages.’

    None of this considers the psychological impact of a streak. The longer a streak goes on, the more stress and nerves are put on a player. At the same time, the more ease is given a player, as the expectation of winning becomes a short-term norm.

    Per FiveThirtyEight, the Cleveland Indians had a 53% chance of winning Game 4 of the ALCS on October 18, 2016. The Epstein family gave it much less of a chance. We were right.