Delete TourDe538.ipynb
This commit is contained in:
1 parent
951ab26992
commit
1331acae2b
1 file changed
-477
-477
@@ -1,477 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<div align=\"right\" style=\"text-align: right\"><i>Peter Norvig<br>Aug 2018</i></div>\n",
|
||||
"\n",
|
||||
"# Tour de 538\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"You are the coach for a bicycle racing team, one of 20 teams entered in the [Tour de FiveThirtyEight](https://fivethirtyeight.com/features/can-you-win-the-tour-de-fivethirtyeight/) time trial, which has these rules:\n",
|
||||
"\n",
|
||||
">*Each team rides as a group throughout the course at some fixed pace, specified by that team’s coach. Teams that can’t maintain their pace are said to have **cracked,** and don’t **finish** the course.\n",
|
||||
"The team that finishes the course with the fastest pace is the winner.\n",
|
||||
"Teams ride the course one at a time. After each team completes its attempt, the next team quickly consults with its coach (who assigns a pace) and then begins its ride. Coaches are aware of the results of all previous teams when choosing their own team’s pace.\n",
|
||||
"Assume that all teams are of equal ability: At any given pace, they have the exact same probability of cracking, and the faster the pace, the greater the probability of cracking. Teams’ chances of cracking are independent, and each team’s coach knows exactly what a team’s chances of cracking are for each pace. You are the first team to attempt the course. To maximize your chances of winning, what’s the probability that your team will finish the course? What’s the probability you’ll ultimately win? How about the other teams?*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# PRELIMINARIES\n",
|
||||
"%matplotlib inline\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import random\n",
|
||||
"from functools import lru_cache\n",
|
||||
"from collections import Counter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Analysis\n",
|
||||
"\n",
|
||||
"At first it might seem like we don't have enough information: we don't know the relation between probability of finishing and the actual pace/speed. But after a little thought, it is clear we don't need to know how fast each team goes. Probability of finishing may not be related linearly to speed, but whatever the function that relates probability of finishing to speed, it is **monotonic**: the the faster the pace, the lower the probability of finishing. Thus, the team that chooses the lowest probability and actually finishes will be the winner (even if we don't know their speed/time).\n",
|
||||
"\n",
|
||||
"Let's start with **a simpler case: just two teams**. The first team chooses a probability $p$ of finishing. If the first team cracks, the second team chooses probability 1 of finishing, rides the race at a nice leisurly pace, and wins. If the first team finishes, the second team chooses probability $p - 𝜖$ of finishing, where 𝜖 is an arbitrarily small number; that gives them an ever-so-slightly-faster pace than the first team. But let's just write $p$ instead of $p - 𝜖$, with the understanding that the $𝜖$ is so small that it doesn't matter for our calculations—another way of saying this is that a tie goes to the team that goes later. So the first team wins if they finish and the second team doesn't, and since \"chances of cracking are independent,\" that joint event has probabilty $p (1 - p)$. What pace $p$ maximizes that? I'm going to enumerate 1001 different $p$ values and find the one that maximizes $p (1 - p)$:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"0.5"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"probabilities = [x/1000 for x in range(1001)] # [0.000, 0.001, 0.002, ... 1.000]\n",
|
||||
"\n",
|
||||
"max(probabilities, key=lambda p: p * (1 - p))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"That says the first team's best choice is a pace that gives them a probability 0.5 of finishing. They win the race with probability 0.5 × (1 - 0.5) = 0.25; the second team wins with probability 0.75. There is value in the information gained by going second! \n",
|
||||
"\n",
|
||||
"Now for **the case of $n$ teams**. The first team wins if they finish (with probability $p$), and if *all* the other teams crack (with probability $(1 - p)^{n - 1}$, assuming they also choose pace $p$). All together, that's $p(1 - p)^{n - 1}$. Again, I can try out all the probabilities in `probabilities` and see which is the best pace for the first team, for various values of `n` teams in the race:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{1: 1.0, 2: 0.5, 3: 0.333, 4: 0.25, 5: 0.2, 6: 0.167}"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def best_pace(n) -> float:\n",
|
||||
" \"\"\"The pace p with highest probability of winning for the first of `n` teams.\"\"\"\n",
|
||||
" return max(probabilities, key=lambda p: win_prob(p, n))\n",
|
||||
"\n",
|
||||
"def win_prob(p, n) -> float:\n",
|
||||
" \"\"\"Probability of first team winning if all n teams choose pace `p`.\"\"\"\n",
|
||||
" return p * (1 - p) ** (n - 1)\n",
|
||||
" \n",
|
||||
"{n: best_pace(n) for n in range(1, 7)}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Notice a pattern? It looks like `best_pace(n)` is $1/n$. But can we prove it? \n",
|
||||
"\n",
|
||||
"# Using Calculus to Find Best Pace \n",
|
||||
"\n",
|
||||
"Calculus says that the extrema (maximum or minimum) of a function is where the derivative is zero. What's the derivative of $p (1 - p)^{n - 1}$?\n",
|
||||
"\n",
|
||||
"$$\\frac{d}{dp} p (1 - p)^{n - 1} = (1 - p)^{n - 2} (1 - n p) $$\n",
|
||||
"\n",
|
||||
"This is indeed zero when $p = 1/n$. We can check that `best_pace(n)` agrees with `1 / n` (to within 3 decimal places):"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"for n in range(1, 21):\n",
|
||||
" assert abs(best_pace(n) - 1/n) < 0.001 "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We now know how every race will play out:\n",
|
||||
"- The first of $n$ teams chooses pace $p = 1/n$.\n",
|
||||
"- If they crack, it is like starting a race with $n - 1$ teams, and the next team chooses pace $1/(n - 1)$.\n",
|
||||
"- If they finish, every team from then on will choose a pace that is $𝜖$ faster than the previous finisher.\n",
|
||||
"- The only way for the first team to win is if every other chooses $p$ and cracks.\n",
|
||||
"- This confirms that the win probability for the first team is $p(1 - p)^{n - 1}$, where $p = 1/n$.\n",
|
||||
"\n",
|
||||
"# Tabulating Results\n",
|
||||
"\n",
|
||||
"We can print a table of three columns: the number of teams $n$, the best pace for the first of $n$ teams, and the probability that the first team will win if it adopts that pace:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" n pace P(win)\n",
|
||||
" 1 1.00000 1.00000\n",
|
||||
" 2 0.50000 0.25000\n",
|
||||
" 3 0.33333 0.14815\n",
|
||||
" 4 0.25000 0.10547\n",
|
||||
" 5 0.20000 0.08192\n",
|
||||
" 6 0.16667 0.06698\n",
|
||||
" 7 0.14286 0.05665\n",
|
||||
" 8 0.12500 0.04909\n",
|
||||
" 9 0.11111 0.04330\n",
|
||||
"10 0.10000 0.03874\n",
|
||||
"11 0.09091 0.03505\n",
|
||||
"12 0.08333 0.03200\n",
|
||||
"13 0.07692 0.02944\n",
|
||||
"14 0.07143 0.02726\n",
|
||||
"15 0.06667 0.02538\n",
|
||||
"16 0.06250 0.02374\n",
|
||||
"17 0.05882 0.02230\n",
|
||||
"18 0.05556 0.02102\n",
|
||||
"19 0.05263 0.01989\n",
|
||||
"20 0.05000 0.01887\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(' n pace P(win)')\n",
|
||||
"for n in range(1, 21):\n",
|
||||
" print(f'{n:2d} {1 / n:0.5f} {win_prob(1 / n, n):0.5f}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Visualizing Results\n",
|
||||
"\n",
|
||||
"Here is a plot for various numbers of teams of the probability of the first team winning, as a function of the pace that the first team chooses. Each curve is for a different number of teams participating in the race (as shown by the label number)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"needs_background": "light"
|
||||
},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def annotate(x, y, text):\n",
|
||||
" plt.text(x - 0.04, y - 0.014, text)\n",
|
||||
" plt.plot([x], [y], 'kx')\n",
|
||||
" \n",
|
||||
"for n in [2, 3, 4, 5, 7, 10, 20]:\n",
|
||||
" plt.plot(probabilities, [win_prob(p, n) for p in probabilities])\n",
|
||||
" annotate(1 / n, win_prob(1 / n, n), f'n={n}')\n",
|
||||
"plt.xlabel('First team pace, denoted by P(finish)')\n",
|
||||
"plt.ylabel('P(first team wins)')\n",
|
||||
"plt.grid(True);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Calculation of Win Probability for All Teams\n",
|
||||
"\n",
|
||||
"What is the full probability distribution of winners over all the teams? I'll define `winners(teams)` to answer the question, where `teams` is a tuple of teams, such as `(1, 2, 3, 4)`. Here's how it works:\n",
|
||||
"- `winners(teams)` gives the probability of winning the race for each team. The result is a `Dist`, a probability distribution of `{team: probability}` pairs. For example, we want `winners((1, 2))` to return `Dist({1: 0.25, 2: 0.75})`.\n",
|
||||
"- A recursive call to `winners(teams, leader, leader_pace)` means that `teams` is the collection of teams who have not raced yet, `leader` is the fastest finishing team among those who have already raced, and `leader_pace` is the pace that the leader rode.\n",
|
||||
"- If there are no `teams` remaining to race, then the winner (with probability 1) is the `leader` so far.\n",
|
||||
"- If there are $n$ teams left to race, then the next team up will choose a pace $p$ that is the faster of $1/n$ and the current leader's pace. \n",
|
||||
"- There are two possible cases to consider:\n",
|
||||
" - That `team` finishes, with probability `p`, and becomes the new leader. The probability distribution in this case is computed by a recursive call `winners(other_teams, team, p)`.\n",
|
||||
" - That `team` cracks, with probability `1 - p`, and the leader is unchanged. The probability distribution in this case is computed by a recursive call `winners(other_teams, leader, leader_pace)`.\n",
|
||||
"- We combine the two cases, weighted by their probability.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Dist(Counter):\n",
|
||||
" \"\"\"A {outcome: frequency} distribution. Can multiply values by a constant.\"\"\"\n",
|
||||
" def __mul__(self, c): return Dist({x: c * self[x] for x in self})\n",
|
||||
" __rmul__ = __mul__\n",
|
||||
" \n",
|
||||
"@lru_cache(None)\n",
|
||||
"def winners(teams, leader=None, leader_pace=1) -> Dist:\n",
|
||||
" \"\"\"Calculate the probability of each team winning.\"\"\"\n",
|
||||
" if not teams:\n",
|
||||
" return Dist({leader: 1})\n",
|
||||
" else:\n",
|
||||
" team, other_teams = teams[0], teams[1:]\n",
|
||||
" p = min(1/len(teams), leader_pace)\n",
|
||||
" finish = winners(other_teams, team, p)\n",
|
||||
" crack = winners(other_teams, leader, leader_pace)\n",
|
||||
" return Dist(p * finish + (1 - p) * crack)\n",
|
||||
" \n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Dist({2: 0.75, 1: 0.25})"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"winners((1, 2))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Simulation of Winners\n",
|
||||
"\n",
|
||||
"As a check, let's do a simulation where each team chooses their `pace`, and we randomly see if they crack, and eventually see who wins the race. Repeat that for a million races and count the winners. I'll define `race` to be as similar to `winners` as possible, but to follow one of the two paths (finish or crack) at random, rather than following both."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def race(teams, leader=None, leader_pace=1):\n",
|
||||
" \"Simulate a single race with given teams; return the winning team.\"\n",
|
||||
" if not teams:\n",
|
||||
" return leader\n",
|
||||
" else:\n",
|
||||
" team, other_teams = teams[0], teams[1:]\n",
|
||||
" p = min(1/len(teams), leader_pace)\n",
|
||||
" return (race(other_teams, team, p) if random.random() < p else\n",
|
||||
" race(other_teams, leader, leader_pace))\n",
|
||||
"\n",
|
||||
"def races(teams, repeat=1000000):\n",
|
||||
" \"Simulate `repeat` races with given teams; return a probability distribution over winners.\"\n",
|
||||
" counts = Counter(race(teams) for _ in range(repeat))\n",
|
||||
" return Dist({team: counts[team] / repeat for team in teams})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Dist({1: 0.249669, 2: 0.750331})"
|
||||
]
|
||||
},
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"races((1, 2))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Comparison of Calculation to Simulation\n",
|
||||
"\n",
|
||||
"Now we can compare the theoretical calculated results with the simulated results:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" n Calcul Simul Delta\n",
|
||||
" 1 0.0189 0.0192 -0.0003\n",
|
||||
" 2 0.0199 0.0200 -0.0001\n",
|
||||
" 3 0.0210 0.0211 -0.0001\n",
|
||||
" 4 0.0223 0.0223 +0.0000\n",
|
||||
" 5 0.0237 0.0237 +0.0000\n",
|
||||
" 6 0.0253 0.0253 -0.0000\n",
|
||||
" 7 0.0270 0.0270 -0.0000\n",
|
||||
" 8 0.0290 0.0289 +0.0001\n",
|
||||
" 9 0.0313 0.0313 +0.0001\n",
|
||||
" 10 0.0340 0.0340 +0.0000\n",
|
||||
" 11 0.0370 0.0371 -0.0001\n",
|
||||
" 12 0.0406 0.0406 -0.0001\n",
|
||||
" 13 0.0448 0.0446 +0.0001\n",
|
||||
" 14 0.0498 0.0499 -0.0001\n",
|
||||
" 15 0.0560 0.0561 -0.0000\n",
|
||||
" 16 0.0639 0.0639 +0.0000\n",
|
||||
" 17 0.0742 0.0739 +0.0003\n",
|
||||
" 18 0.0889 0.0889 -0.0001\n",
|
||||
" 19 0.1126 0.1122 +0.0003\n",
|
||||
" 20 0.1799 0.1801 -0.0003\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"needs_background": "light"
|
||||
},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def compare(teams=range(1, 21)):\n",
|
||||
" \"\"\"Print and plot comparison between `races` simulation and `winners` calculation.\"\"\"\n",
|
||||
" wins = winners(teams)\n",
|
||||
" sims = races(teams)\n",
|
||||
" print(f' n Calcul Simul Delta')\n",
|
||||
" for team in teams:\n",
|
||||
" print(f'{team:3d} {wins[team]:.4f} {sims[team]:.4f} {wins[team]-sims[team]:+.4f}')\n",
|
||||
" plt.plot(teams, [wins[i] for i in teams], 'rx', label='calculation', ms=10, mew=2)\n",
|
||||
" plt.plot(teams, [sims[i] for i in teams], 'b+', label='simulation', ms=10, mew=2)\n",
|
||||
" plt.xticks(ticks=teams); plt.grid(True);\n",
|
||||
" plt.xlabel('Team Number'); plt.ylabel('P(win)'); plt.legend()\n",
|
||||
"\n",
|
||||
"compare()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We see there is excellent agreement The `×` and `+` markers are all on top of each other. The agreement extends to a different number of teams:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" n Calcul Simul Delta\n",
|
||||
" 1 0.0387 0.0387 +0.0001\n",
|
||||
" 2 0.0433 0.0434 -0.0001\n",
|
||||
" 3 0.0489 0.0489 -0.0000\n",
|
||||
" 4 0.0561 0.0554 +0.0007\n",
|
||||
" 5 0.0653 0.0657 -0.0004\n",
|
||||
" 6 0.0775 0.0769 +0.0006\n",
|
||||
" 7 0.0945 0.0948 -0.0003\n",
|
||||
" 8 0.1198 0.1198 +0.0001\n",
|
||||
" 9 0.1629 0.1633 -0.0004\n",
|
||||
" 10 0.2929 0.2931 -0.0002\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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Bsya1SEo3IO7t4G9gTFrVt5Hbyoswsu6spdeChJ51arglafLuTPOOIPGxkY2b94MwDvvvMO7777LkUcGU13df//9nR535plncvfddwPBdBrvvvsulZWVtLW1sXnzZt5//30eeeSRfY7LBMPQoUPZtm1bhxFShx56KFu3bt3nmPHjx/O73/2Ot99+m927dzN//nwmTpzY63+ziCRoxozum8crKhIZ5l/aYRFp/9t93HF707qzuyR7GRijRo3iG9/4BhMnTqS6upprrrmGm2++mfr6empqatqbp7LdeeedNDU1MWbMGGpqalizZg0DBgzgpptuYvz48Zx99tkcd9xx+xz3sY99jMsvv5zRo0dzzjnncPLJJ7dvu/TSS7niiivaO7gzPvGJT3DrrbdSV1dHdXU1Y8eOZcqUKft8toiUsFzmBDkQXp3NDbVmzZruJ0WZNat9HpWtr7227/boXCuzZnX/WXlwIM4NlRH7u+6Fkp3/pwuqI101uPeNOshxbqg+81jVXslcqtXX45HRQe0yVxiNjbp7W0RKWmmHBewNgU7a8oHE2v9ERA4kpd1nISIiOVFYiIhILIWFiIjEUlhkMctMASwiIhkKiyLI59TgI0aM4O233+52n+9+97sdlj/zmc/k5dwiUjoUFkVQ6KnBs8Pi6aefLti5RaRvUFgkbPv27Zx33nlUV1czevRoHnrooQ5Tg5eXlzNz5kxGjRrF5MmTee6556itreXoo49m4cLgkeX33Xdfh4cinX/++TQ3N+9zri984QvU1NQwatQofvzjHwNw/fXXs2PHDsaOHctFF13Ufk4IbsicOXMmo0ePZsyYMTz00EMAPPXUU9TW1jJt2jSOO+44LrroIjyJCfJF5IBR8mGR6aP4yEcO7dBXkVm/v30Yjz76KEcccQQrVqxg1apVTJo0qcP27du3c8YZZ7B69WrKy8u58cYbefzxx1mwYEGH50rkYu7cuSxbtoylS5dy1113sXnzZm699VYOPvhgWlpaeOCBBzrs/8tf/pKWlhZWrFjBE088wcyZM/nTn/4EwPPPP88Pf/hD1qxZw7p16/jDH/7Q+1+CiBzwSj4skjZmzBgef/xxrrvuOp566ql9phofOHBge4BUVVUxceJEBgwYwJgxY3o8Hfhdd93V/pCi9evX8+qrr3a7/+9//3suvPBCysrKqKysZOLEiSxZsgQIJhccPnw4/fr1Y+zYsZqaXKTElfwd3JnWla1bt3LooXuvLvLV6nLssceyfPlyFi1axI033siZZ57ZYXt0CvB+/fpx0EEHtb/PTAeey9Tkzc3NPPHEEzzzzDMccsgh1NbW7tfU5Jk6QFOTi4iuLBK3ceNGDjnkEL70pS8xc+ZMli9f3uPPGDFiBC0tLezZs4f169fz3HPP7bPPu+++y5AhQzjkkEN46aWXePbZZ9u3DRgwgA8//HCfYz73uc/x0EMPsXv3bjZt2sSTTz7J+PHje1yfiPR9JX9lkbSVK1cyc+ZM+vXrx4ABA7j77ru59tpre/QZp512GiNHjqSqqorjjz+ek046aZ99Jk2axI9+9COOP/54Pv3pT3PKKae0b5s+fTonnHACJ510Uod+i6lTp/LMM89QXV2NmXHbbbfx8Y9/vPf/WBHpu3KZmvZAePVqivKIzLTcQQNUzofllaYo76gvTP+cT6ojXTW494060BTlvaMRoiIi+1KfhYiIxOrzYeG6VEicfscifV+fDotBgwaxefNmfZklyN3ZvHkzgwYNKnYpIpKgPt1nMXz4cDZs2MCmTZti9925c2fRv/DSUENv6hg0aBDDhw9PsCIRKbY+HRYDBgxg5MiROe3b3NzMiSeemHBF6a8hTXWISHok2gxlZpPM7GUzW2tm13ey/RozW2NmL5jZb83sqMi23WbWEr4WJlmniIh0L7ErCzMrA2YDZwMbgCVmttDdow9yeB4Y5+5/MbOvArcB/zPctsPdxyZVn4iI5C7JK4vxwFp3X+fuHwDzgCnRHdy9yd3/Ei4+C6jhW0QkhZIMiyOB9ZHlDeG6rnwZ+M/I8iAzW2pmz5rZF5IoUEREcmNJDSs1s2nAJHe/LFy+GJjg7g2d7PsloAGY6O7vh+uOdPe3zOxoYDFwpru/lnXcdGA6QGVlZc28efN6Xe+2bdvaHwpULGmoQXWojgOhjjTU0FfqqKurW+bu42J3zGVOkN68gFOBxyLLNwA3dLLfWcCLQEU3n3UfMK2783U2N1RPpGGOlzTU4K46sqmOjtJQRxpqcO8bdZDj3FBJNkMtAY4xs5FmNhC4AOgwqsnMTgTuASa7e1tk/RAzOyh8PxQ4DYh2jIuISAElNhrK3XeZWQPwGFAGzHX31WZ2C0GSLQRuB8qBxvABQG+6+2TgeOAeM9tD0K9yq3ccRSUiIgWU6E157r4IWJS17qbI+7O6OO5pYEyStYmISO769NxQIiKSHwoLERGJpbAQEZFYCgsREYmlsBARkVgKCxERiaWwEBGRWAoLERGJpbAQEZFYCgsREYmlsBARkVgKCxERiaWwEBGRWAoLERGJpbAQEZFYCgsREYmlsBARkVgKCxERiaWLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"needs_background": "light"
|
||||
},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"compare(range(1, 11))"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.2"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
Reference in new issue
Block a user