Spaces:
Running
Running
| # /// script | |
| # requires-python = ">=3.10" | |
| # dependencies = [ | |
| # "marimo", | |
| # ] | |
| # /// | |
| import marimo | |
| __generated_with = "0.11.0" | |
| app = marimo.App() | |
| def _(mo): | |
| mo.md( | |
| r""" | |
| # Sets | |
| Probability is the study of "events", assigning numerical values to how likely | |
| events are to occur. For example, probability lets us quantify how likely it is for it to rain or shine on a given day. | |
| Typically we reason about _sets_ of events. In mathematics, | |
| a set is a collection of elements, with no element included more than once. | |
| Elements can be any kind of object. | |
| For example: | |
| - โ๏ธ Weather events: $\{\text{Rain}, \text{Overcast}, \text{Clear}\}$ | |
| - ๐ฒ Die rolls: $\{1, 2, 3, 4, 5, 6\}$ | |
| - ๐ช Pairs of coin flips = $\{ \text{(Heads, Heads)}, \text{(Heads, Tails)}, \text{(Tails, Tails)} \text{(Tails, Heads)}\}$ | |
| Sets are the building blocks of probability, and will arise frequently in our study. | |
| """ | |
| ) | |
| return | |
| def _(mo): | |
| mo.md(r"""## Set operations""") | |
| return | |
| def _(mo): | |
| mo.md(r"""In Python, sets are made with the `set` function:""") | |
| return | |
| def _(): | |
| A = set([2, 3, 5, 7]) | |
| A | |
| return (A,) | |
| def _(): | |
| B = set([0, 1, 2, 3, 5, 8]) | |
| B | |
| return (B,) | |
| def _(mo): | |
| mo.md( | |
| r""" | |
| Below we explain common operations on sets. | |
| _**Try it!** Try modifying the definitions of `A` and `B` above, and see how the results change below._ | |
| The **union** $A \cup B$ of sets $A$ and $B$ is the set of elements in $A$, $B$, or both. | |
| """ | |
| ) | |
| return | |
| def _(A, B): | |
| A | B | |
| return | |
| def _(mo): | |
| mo.md(r"""The **intersection** $A \cap B$ is the set of elements in both $A$ and $B$""") | |
| return | |
| def _(A, B): | |
| A & B | |
| return | |
| def _(mo): | |
| mo.md(r"""The **difference** $A \setminus B$ is the set of elements in $A$ that are not in $B$.""") | |
| return | |
| def _(A, B): | |
| A - B | |
| return | |
| def _(mo): | |
| mo.md( | |
| """ | |
| ### ๐ฌ An interactive example | |
| Here's a simple example that classifies TV shows into sets by genre, and uses these sets to recommend shows to a user based on their preferences. | |
| """ | |
| ) | |
| return | |
| def _(mo): | |
| viewer_type = mo.ui.radio( | |
| options={ | |
| "I like action and drama!": "New Viewer", | |
| "I only like action shows": "Action Fan", | |
| "I only like dramas": "Drama Fan", | |
| }, | |
| value="I like action and drama!", | |
| label="Which genre do you prefer?", | |
| ) | |
| return (viewer_type,) | |
| def _(viewer_type): | |
| viewer_type | |
| return | |
| def _(): | |
| action_shows = {"Stranger Things", "The Witcher", "Money Heist"} | |
| drama_shows = {"The Crown", "Money Heist", "Bridgerton"} | |
| return action_shows, drama_shows | |
| def _(action_shows, drama_shows): | |
| recommendations = { | |
| "New Viewer": action_shows | drama_shows, # Union for new viewers | |
| "Action Fan": action_shows - drama_shows, # Unique action shows | |
| "Drama Fan": drama_shows - action_shows, # Unique drama shows | |
| } | |
| return (recommendations,) | |
| def _(mo, recommendations, viewer_type): | |
| result = recommendations[viewer_type.value] | |
| explanation = { | |
| "New Viewer": "You get everything to explore!", | |
| "Action Fan": "Pure action, no drama!", | |
| "Drama Fan": "Drama-focused selections!", | |
| } | |
| mo.md(f""" | |
| **๐ฌ Recommended shows.** Based on your preference for **{viewer_type.value}**, | |
| we recommend: | |
| {", ".join(result)} | |
| **Why these shows?** | |
| {explanation[viewer_type.value]} | |
| """) | |
| return explanation, result | |
| def _(mo): | |
| mo.md(""" | |
| ### Exercise | |
| Given these sets: | |
| - A = {๐ฎ, ๐ฑ, ๐ป} | |
| - B = {๐ฑ, ๐ป, ๐จ๏ธ} | |
| - C = {๐ป, ๐จ๏ธ, โจ๏ธ} | |
| Can you: | |
| 1. Find all elements that are in A or B | |
| 2. Find elements common to all three sets | |
| 3. Find elements in A that aren't in C | |
| <details> | |
| <summary>Check your answers!</summary> | |
| 1. A โช B = {๐ฎ, ๐ฑ, ๐ป, ๐จ๏ธ}<br> | |
| 2. A โฉ B โฉ C = {๐ป}<br> | |
| 3. A - C = {๐ฎ, ๐ฑ} | |
| </details> | |
| """) | |
| return | |
| def _(mo): | |
| mo.md( | |
| r""" | |
| ## ๐งฎ Set properties | |
| Here are some important properties of the set operations: | |
| 1. **Commutative**: $A \cup B = B \cup A$ | |
| 2. **Associative**: $(A \cup B) \cup C = A \cup (B \cup C)$ | |
| 3. **Distributive**: $A \cup (B \cap C) = (A \cup B) \cap (A \cup C)$ | |
| """ | |
| ) | |
| return | |
| def _(mo): | |
| mo.md( | |
| r""" | |
| ## Set builder notation | |
| To compactly describe the elements in a set, we can use **set builder notation**, which specifies conditions that must be true for elements to be in the set. | |
| For example, here is how to specify the set of positive numbers less than 10: | |
| \[ | |
| \{x \mid 0 < x < 10 \} | |
| \] | |
| The predicate to the right of the vertical bar $\mid$ specifies conditions that must be true for an element to be in the set; the expression to the left of $\mid$ specifies the value being included. | |
| In Python, set builder notation is called a "set comprehension." | |
| """ | |
| ) | |
| return | |
| def _(): | |
| def predicate(x): | |
| return x > 0 and x < 10 | |
| return (predicate,) | |
| def _(predicate): | |
| set(x for x in range(100) if predicate(x)) | |
| return | |
| def _(mo): | |
| mo.md("""**Try it!** Try modifying the `predicate` function above and see how the set changes.""") | |
| return | |
| def _(mo): | |
| mo.md(""" | |
| ## Summary | |
| You've learned: | |
| - Basic set operations | |
| - Set properties | |
| - Real-world applications | |
| In the next lesson, we'll define probability from the ground up, using sets. | |
| Remember: In probability, every event is a set, and every set can be an event! | |
| """) | |
| return | |
| def _(): | |
| import marimo as mo | |
| return (mo,) | |
| if __name__ == "__main__": | |
| app.run() | |