```
%pylab inline
figsize(12.5,4)
```

    Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.zmq.pylab.backend_inline].
    For more information, type 'help(pylab)'.

Chapter 1
======
***

The Philosophy of Bayesian Inference
------

> You are a skilled programmer, but bugs still slip into your code. After a particularly difficult implementation of an algorithm, you decide to test your code on a trivial example. It passes. You test the code on a harder problem. It passes once again. And it passes the next, *even more difficult*, test too! You are starting to believe that there may be no bugs in this code...

If you think this way, then congratulations, you already are a Bayesian practitioner! Bayesian inference is simply updating your beliefs after considering new evidence. A Bayesian can rarely be certain about a result, but he or she can be very confident. Just like in the example above, we can never be 100% sure that our code is bug-free unless we test it on every possible problem; something rarely possible in practice. Instead, we can test it on a large number of problems, and if it succeeds we can feel more *confident* about our code.  Bayesian inference works identically: we update our beliefs about an outcome; rarely can we be absolutely sure unless we rule out all other alternatives.

###The Bayesian state of mind

Bayesian inference differs from more traditional statistical inference by preserving *uncertainty* about our beliefs. At first, this sounds like a bad statistical technique. Isn't statistics all about deriving *certainty* from randomness? To reconcile this, we need to start thinking like Bayesians.

The Bayesian world-view interprets probability as measure of *believability in an event*, that is, how confident we are in an event occurring. In fact, we will see in a moment that this is the natural interpretation of probability.

For this to be clearer, we consider an alternative interpretation of probability: *Frequentist* methods assume that probability is the long-run frequency of events (hence the bestowed title). For example, the *probability of plane accidents* under a frequentist philosophy is interpreted as the *long-term frequency of plane accidents*. This makes logical sense for many probabilities of events, but becomes more difficult to understand when events have no long-term frequency of occurrences. Consider: we often assign probabilities to outcomes of presidential elections, but the election itself only happens once! Frequentists get around this by invoking alternative realities and saying across all these universes, the frequency of occurrences defines the probability.

Bayesians, on the other hand, have a more intuitive approach. Bayesians interpret a probability as measure of *belief*, or confidence, of an event occurring. An individual who assigns a belief of 0 to an event has no confidence that the event will occur; conversely, assigning a belief of 1 implies that the individual is absolutely certain of an event occurring. Beliefs between 0 and 1 allow for weightings of other outcomes. This definition agrees with the probability of a plane accident example, for having observed the frequency of plane accidents, an individual's belief should be equal to that frequency, excluding any outside information. Similarly, under this definition of probability being equal to beliefs, it is clear how we can speak about probabilities (beliefs) of presidential election outcomes: how confident are you candidate A will win?

Notice in the paragraph above, I assigned the belief (probability) measure to an *individual*, not to Nature. This is very interesting, as this definition leaves room for conflicting beliefs between individuals. Again, this is appropriate for what naturally occurs: different individuals have different beliefs of events occurring, because they possess different *information* about the world. Consider the following examples demonstrating the relationship between individual beliefs and probabilities:

- I flip a coin, and we both guess the result. We would both agree, assuming the coin is fair, that the probability of heads is 1/2. Assume, then, that I peek at the coin. Now I know for certain what the result is: I assign probability 1.0 to either heads or tails. Now what is *your* belief that the coin is heads? My knowledge of the outcome has not changed the coin's results. Thus we assign different probabilities to the result.

-  Your code either has a bug in it or not, but we do not know for certain which is true. Though we have a belief about the presence or absence of a bug.

-  A medical patient is exhibiting symptoms $x$, $y$ and $z$. There are a number of diseases that could be causing all of them, but only a single disease is present. A doctor has beliefs about which disease.

This philosophy of treating beliefs as probability is natural to humans. We employ it constantly as we interact with the world and only see partial evidence. Alternatively, you have to be *trained* to think like a frequentist.

To align ourselves with traditional probability notation, we denote our belief about event $A$ as $P(A)$. We call this quantity the *prior probability*.

John Maynard Keynes, a great economist and thinker, said "When the facts change, I change my mind. What do you do, sir?" This quote reflects the way a Bayesian updates his or her beliefs after seeing evidence. Even --especially-- if the evidence is counter to what was initially believed, the evidence cannot be ignored. We denote our updated belief as $P(A |X )$, interpreted as the probability of $A$ given the evidence $X$. We call the updated belief the *posterior probability* so as to contrast it with the prior probability. For example, consider the posterior probabilities (read: posterior beliefs) of the above examples, after observing some evidence $X$.:

1\. $P(A): \;\;$ the coin has a 50 percent chance of being heads. $P(A | X):\;\;$ You look at the coin, observe a heads has landed, denote this information $X$, and trivially assign probability 1.0 to heads and 0.0 to tails.

2\.   $P(A): \;\;$  This big, complex code likely has a bug in it. $P(A | X): \;\;$ The code passed all $X$ tests; there still might be a bug, but its presence is less likely now.

3\.  $P(A):\;\;$ The patient could have any number of diseases. $P(A | X):\;\;$ Performing a blood test generated evidence $X$, ruling out some of the possible diseases from consideration.

It's clear that in each example we did not completely discard the prior belief after seeing new evidence $X$, but we *re-weighted the prior* to incorporate the new evidence (i.e. we put more weight, or confidence, on some beliefs versus others).

By introducing prior uncertainty about events, we are already admitting that any guess we make is potentially very wrong. After observing data, evidence, or other information, we update our beliefs, and our guess becomes *less wrong*. This is the alternative side of the prediction coin, where typically we try to be *more right*.

###Bayesian Inference in Practice

 If frequentist and Bayesian inference were programming functions, with inputs being statistical problems, then the two would be different in what they return to the user. The frequentist inference function would return a number, whereas the Bayesian function would return *probabilities*.

For example, in our debugging problem above, calling the frequentist function with the argument "My code passed all $X$ tests; is my code bug-free?" would return a *YES*. On the other hand, asking our Bayesian function "Often my code has bugs. My code passed all $X$ tests; is my code bug-free?" would return something very different: a probabilities of *YES* and *NO*. The function might return:

>    *YES*, with probability 0.8; *NO*, with probability 0.2

This is very different from the answer the frequentist function returned. Notice that the Bayesian function accepted an additional argument:  *"Often my code has bugs"*. This parameter is the *prior*. By including the prior parameter, we are telling the Bayesian function to include our belief about the situation. Technically this parameter in the Bayesian function is optional, but we will see excluding it has its own consequences.

####Incorporating evidence

As we acquire more and more instances of evidence, our prior belief is *washed out* by the new evidence. This is to be expected. For example, if your prior belief is something ridiculous, like "I expect the sun to explode today", and each day you are proved wrong, you would hope that any inference would correct you, or at least align your beliefs better. Bayesian inference will correct this belief.

Denote $N$ as the number of instances of evidence we possess. As we gather an *infinite* amount of evidence, say as $N \rightarrow \infty$, our Bayesian results align with frequentist results. Hence for large $N$, statistical inference is more or less objective. On the other hand, for small $N$, inference is much more *unstable*: frequentist estimates have more variance and larger confidence intervals. This is where Bayesian analysis excels. By introducing a prior, and returning probabilities (instead of a scalar estimate), we *preserve the uncertainty* that reflects the instability of stastical inference of a small $N$ dataset.

One may think that for large $N$, one can be indifferent between the two techniques since they offer similar inference, and might lean towards the computational-simpler, frequentist methods. An individual in this position should consider the following quote by Andrew Gelman (2005)[1], before making such a decision:

> Sample sizes are never large. If $N$ is too small to get a sufficiently-precise estimate, you need to get more data (or make more assumptions). But once $N$ is "large enough," you can start subdividing the data to learn more (for example, in a public opinion poll, once you have a good estimate for the entire country, you can estimate among men and women, northerners and southerners, different age groups, etc.). $N$ is never enough because if it were "enough" you'd already be on to the next problem for which you need more data.

### Are frequentist methods incorrect then?

**No.**

Frequentist methods are still useful or state-of-the-art in many areas. Tools like Least Squares linear regression, LASSO regression, EM algorithm etc. are all very powerful and incredibly fast. Bayesian methods are a compliment to solve the problems these solutions cannot or to gain further insight into the underlying system by offering more flexibility in modeling.

#### A note on *Big Data*
Paradoxically, big data's predictive analytic problems are actually solved by relatively simple algorithms [2][4]. Thus we can argue that big data's prediction difficulty does not lie in the algorithm used, but instead on the computational difficulties of storage and execution on big data. (One should also consider Gelman's quote from above and ask "Do I really have big data?" )

The much more difficult analytic problems involve *medium data* and, especially troublesome, *really small data*. Using a similar argument as  Gelman's above, if big data problems are *big enough* to be readily solved, then we should be more interested in the *not-quite-big enough* datasets.

### Our Bayesian framework

We are interested in beliefs, which can be interpreted as probabilities by thinking Bayesian. We have a *prior* belief in event $A$, beliefs formed by previous information, e.g., our prior belief about bugs being in our code before performing tests.

Secondly, we observe our evidence. To continue our buggy-code example: if our code passes $X$ tests, we want to update our belief to incorporate this. We call this new belief the *posterior* probability. Updating our belief is done via the following equation, known as Bayes' Theorem, after it's discoverer Thomas Bayes:

\begin{align}
 P( A | X ) = & \frac{ P(X | A) P(A) } {P(X) } \\\\[5pt]
& \propto P(X | A) P(A)\;\; (\propto \text{is proportional to } )
\end{align}

The above formula is not unique to Bayesian inference: it is a mathematical fact with uses outside Bayesian inference. Bayesian inference merely uses it to connect prior probabilities $P(A)$ with an updated posterior probabilities $P(A | X )$.

##### Example: Mandatory coin-flip example

Since every statistics text must contain a coin-flipping example, I'll use it here to get it out of the way. Suppose, naively, that you are unsure what the ratio of heads is in a coin flip (spoiler alert: it's 50%). You believe there is some true underlying ratio, call it $p$, but have no guess apriori.  We begin to flip a coin, and record the observations: this is our data. How does our inference change as we observe more and more data? More specifically, what do our posterior probabilities look like?

Below we plot a sequence of updating posteriors as we observe data (coin flips).

```
"""
The book uses a custom matplotlibrc file, which provides the unique styles for matplotlib plots.
If executing this book, and you wish to use the book's styling, provided are two options:
    1. Overwrite your own matplotlibrc file with the rc-file provided in the book's styles/ dir.
       See http://matplotlib.org/users/customizing.html
    2. Also in the styles is  bmh_matplotlibrc.json file. This can be used to update the styles
       in only this notebook. Try running the following code:

            import json
            s = json.load( open("../styles/bmh_matplotlibrc.json") )
            matplotlib.rcParams.update(s)
"""
#the code below can be passed over, as it is currently not important.
figsize( 11, 9)

import scipy.stats as stats
dist = stats.beta
#n_trials = [0,1, 2 ,4, 8, 16, 32, 64, 128, 500]
n_trials = [0,1,2,3,4,5,6,7, 50, 500]
data = stats.bernoulli.rvs(0.5, size = n_trials[-1] )

x = np.linspace(0,1,100)
#y_prior = np.nan*np.ones( 100 )

for k, N in enumerate(n_trials):
    sx = subplot( len(n_trials)/2, 2, k+1)

    plt.setp(sx.get_yticklabels(), visible=False)
    heads = data[:N].sum()
    y = dist.pdf(x, 1 + heads, 1 + N - heads )
    plt.plot( x, y, label= "observe %d tosses,\n %d heads"%(N,heads) )
    plt.fill_between( x, 0, y, color="#348ABD", alpha = 0.4 )
    plt.vlines( 0.5, 0, 4, color = "k", linestyles = "--", lw=1 )

    leg = plt.legend()
    leg.get_frame().set_alpha(0.4)

plt.suptitle( "Bayesian updating of posterior probabilties",
              y = 1.02,
              fontsize = 14);

plt.tight_layout()
```

As the plot above shows, as we start to observe data, our posterior probabilities, represented as the above curves, start to shift and move around. Eventually, as we observe more and more data, our probabilities will lump closer and closer around the true value of $p=0.5$ (marked by a dashed line).

Notice that the graph is not always *peaked* at 0.5. Apriori, there is no reason it should be. Remember we do not know what $p$ is, we only have seen the data. In fact, if we observe quite extreme data, say 8 flips and only 1 observed heads, our distribution would look very biased *away* from lumping around 0.5.

That being said, it does assign a positive probability to $p$ really being 0.5. As more data accumulates, we would see more and more probabilitiy being assigned at $p=0.5$.

The next example is a simple demonstration of the mathematics of Bayesian updating.

#####Example: Bug, or just sweet, unintended feature?

Let $A$ denote the event that our code has **no bugs** in it. Let $X$ denote the event that the code passes all debugging tests. For now, we will leave the prior probability of no bugs as a variable, i.e. $P(A) = p$.

We are interested in $P(A|X)$, i.e. the probability of no bugs, given our debugging tests $X$. To use the formula above, we need to compute some quantities.

What is $P(X | A)$, i.e., the probability that the code passes $X$ tests *given* there are no bugs? Well, it is equal to 1, for a code with no bugs will pass all tests.

$P(X)$ is a little bit trickier: The event $X$ can be divided into two possibilities, event $X$ occurring even though our code *indeed has* bugs (denoted $\sim A\;$, spoken *not $A$*), or event $X$ without bugs ($A$). $P(X)$ can be represented as:

\begin{align}
P(X ) & = P(X \text{ and } A) + P(X \text{ and } \sim A) \\\\[5pt]
 & = P(X|A)P(A) + P(X | \sim A)P(\sim A)\\\\[5pt]
& = P(X|A)p + P(X | \sim A)(1-p)
\end{align}

We have already computed $P(X|A)$ above. On the other hand, $P(X | \sim A)$ is subjective: our code can pass tests but still have a bug in it, though the probability there is a bug present is reduced. Note this is dependent on the number of tests performed, the degree of complication in the tests, etc. Let's be conservative and assign $P(X|\sim A) = 0.5$. Then

\begin{align}
P(A | X) & = \frac{1\cdot p}{ 1\cdot p +0.5 (1-p) } \\\\
& = \frac{ 2 p}{1+p}
\end{align}
This is the posterior probability. What does it look like as a function of our prior, $p \in [0,1]$?

```
figsize( 12, 4 )
p = np.linspace( 0,1, 50)
plt.plot( p, 2*p/(1+p), color = "#348ABD", lw = 3 )
plt.fill_between( p, 2*p/(1+p), alpha = .2, facecolor = ["#348ABD"])
plt.scatter( 0.2, 2*(0.2)/1.2, s = 140, c ="#348ABD"  )
plt.xlim( 0, 1)
plt.ylim( 0, 1)
plt.xlabel( "Prior, $P(A) = p$")
plt.ylabel("Posterior, $P(A|X)$, with $P(A) = p$")
plt.title( "Are there bugs in my code?");
```

We can see the biggest gains if we observe the $X$ tests passed when the prior probability, $p$, is low. Let's settle on a specific value for the prior. I'm a strong programmer (I think), so I'm going to give myself a realistic prior of 0.20, that is, there is a 20% chance that I write code bug-free. To be more realistic, this prior should be a function of how complicated and large the code is, but let's pin it at 0.20. Then my updated belief that my code is bug-free is 0.33.

Recall that the prior is a probability: $p$ is the prior probability that there *are no bugs*, so $1-p$ is the prior probability that there *are bugs*.

Similarly, our posterior is also a probability, with $P(A | X)$ the probability there is no bug *given we saw all tests pass*, hence $1-P(A|X)$ is the probability there is a bug *given all tests passed*. What does our posterior probability look like? Below is a graph of both the prior and the posterior probabilities.

```
figsize( 9, 4 )
colours = ["#348ABD", "#A60628"]

prior = [0.20, 0.80]
posterior =  [1./3, 2./3]
plt.bar( [0,.7], prior ,alpha = 0.60, width = 0.25, \
            color = colours[0], label = "prior distribution",
             lw = "3", edgecolor = colours[0])

plt.bar( [0+0.25,.7+0.25], posterior ,alpha = 0.5, \
          width = 0.25, color =  colours[1],
          label = "posterior distribution",
          lw = "3", edgecolor = colours[1])

plt.xticks( [0.20,.95], ["Bugs Absent", "Bugs Present"] )
plt.title("Prior and Posterior probability of bugs present, prior = 0.2")
plt.ylabel("Probability")
plt.legend(loc="upper left");
```

Notice that after we observed $X$ occur, the probability of bugs being absent increased. By increasing the number of tests, we can approach confidence (probability 1) that there are no bugs present.

This was a very simple example of Bayesian inference and Bayes rule. Unfortunately, the mathematics necessary to perform more complicated Bayesian inference only becomes more difficult, except for artificially constructed cases. We will later see that this type of mathematical analysis is actually unnecessary. First we must broaden our modeling tools. The next section deals with *probability distributions*. If you are already familiar, feel free to skip (or at least skim), but for the less familiar the next section is essential.

_______

##Probability Distributions

**Let's quickly recall what a probability distribution is:** Let $Z$ be some random variable. Then associated with $Z$ is a *probability distribution function* that assigns probabilities to the different outcomes $Z$ can take. There are three cases:

-   **$Z$ is discrete**: Discrete random variables may only assume values on a specified list. Things like populations, movie ratings, and number of votes are all discrete random variables. Discrete random variables become more clear when we contrast them with...

-   **$Z$ is continuous**: Continuous random variable can take on arbitrarily exact values. For example, temperature, speed, time, color are all modeled as continuous variables because you can constantly make the values more and more precise.

- **$Z$ is mixed**: Mixed random variables assign probabilities to both discrete and continuous random variables, i.e. is is a combination of the above two categories.

###Discrete Case
If $Z$ is discrete, then its distribution is called a *probability mass function*, which measures the probability $Z$ takes on the value $k$, denoted $P(Z=k)$. Note that the probability mass function completely describes the random variable $Z$, that is, if we know the mass function, we know how $Z$ should behave. There are popular probability mass functions that consistently appear: we will introduce them as needed, but let's introduce the first very useful probability mass function. We say $Z$ is *Poisson*-distributed if:

$$P(Z = k) =\frac{ \lambda^k e^{-\lambda} }{k!}, \; \; k=0,1,2, \dots $$

What is $\lambda$? It is called the parameter, and it describes the shape of the distribution. For the Poisson random variable, $\lambda$ can be any positive number. By increasing $\lambda$, we add more probability to larger values, and conversely by decreasing $\lambda$ we add more probability to smaller values. Unlike $\lambda$, which can be any positive number, $k$ must be a non-negative integer, i.e., $k$ must take on values 0,1,2, and so on. This is very important, because if you wanted to model a population you could not make sense of populations with 4.25 or 5.612 members.

If a random variable $Z$ has a Poisson mass distribution, we denote this by writing

$$Z \sim \text{Poi}(\lambda) $$

One very useful property of the Poisson random variable, given we know $\lambda$, is that its expected value is equal to the parameter, ie.:

$$E\large[ \;Z\; | \; \lambda \;\large] = \lambda $$

We will use this property often, so it's something useful to remember. Below we plot the probability mass distribution for different $\lambda$ values. The first thing to notice is that by increasing $\lambda$ we add more probability to larger values occurring. Secondly, notice that although the graph ends at 15, the distributions do not. They assign positive probability to every non-negative integer.

```
figsize( 12.5, 4)

import scipy.stats as stats
a = np.arange( 16 )
poi = stats.poisson
lambda_ = [1.5, 4.25 ]

plt.bar( a, poi.pmf( a, lambda_[0]), color=colours[0],
        label = "$\lambda = %.1f$"%lambda_[0], alpha = 0.60,
        edgecolor = colours[0], lw = "3")

plt.bar( a, poi.pmf( a, lambda_[1]), color=colours[1],
         label = "$\lambda = %.1f$"%lambda_[1], alpha = 0.60,
          edgecolor = colours[1], lw = "3")

plt.xticks( a + 0.4, a )
plt.legend()
plt.ylabel("probability of $k$")
plt.xlabel("$k$")
plt.title("Probability mass function of a Poisson random variable; differing \
$\lambda$ values");
```

###Continuous Case
Instead of a probability mass function, a continuous random variable has a *probability density function*. This might seem like unnecessary nomenclature, but the density function and the mass function are very different creatures. An example of continuous random variable is a random variable with a *exponential density*. The density function for an exponential random variable looks like:

$$f_Z(z | \lambda) = \lambda e^{-\lambda z }, \;\; z\ge 0$$

Like the Poisson random variable, an exponential random variable can only take on non-negative values. But unlike a Poisson random variable, the exponential can take on *any* non-negative values, like 4.25 or 5.612401. This makes it a poor choice for count data, which must be integers, but a great choice for time data, or temperature data (measured in Kelvins, of course), or any other precise *and positive* variable. Below are two probability density functions with different $\lambda$ value.

When a random variable $Z$ has an exponential distribution with parameter $\lambda$, we say *$Z$ is exponential* and write

$$Z \sim \text{Exp}(\lambda)$$

Given a specific $\lambda$, the expected value of an exponential random variable is equal to the inverse of $\lambda$, that is:

$$E[\; Z \;|\; \lambda \;] = \frac{1}{\lambda}$$

```
a = np.linspace(0,4, 100)
expo = stats.expon
lambda_ = [0.5, 1]

for l,c in zip(lambda_,colours):
    plt.plot( a, expo.pdf( a, scale=1./l), lw=3,
                color=c, label = "$\lambda = %.1f$"%l)
    plt.fill_between( a, expo.pdf( a, scale=1./l), color=c, alpha = .33)

plt.legend()
plt.ylabel("PDF at $z$")
plt.xlabel("$z$")
plt.title("Probability density function of an Exponential random variable;\
 differing $\lambda$");
```

###But what is $\lambda \;$?

**This question is what motivates statistics**. In the real world, $\lambda$ is hidden from us. We only see $Z$, and must go backwards to try and determine $\lambda$. The problem is so difficult because there is not a one-to-one mapping from $Z$ to $\lambda$. Many different methods have been created to solve the problem of estimating $\lambda$, but since $\lambda$ is never actually observed, no one can say for certain which method is better!

Bayesian inference is concerned with *beliefs* about what $\lambda$ is. Rather than try to guess $\lambda$ exactly, we can only talk about what $\lambda$ is likely to be by assigning a probability distribution to $\lambda$.

This might seem odd at first: after all, $\lambda$ is fixed, it is not (necessarily) random! How can we assign probabilities to a non-random event. Ah, we have fallen for the frequentist interpretation. Recall, under our Bayesian philosophy, we *can* assign probabilities if we interpret them as beliefs. And it is entirely acceptable to have *beliefs* about the parameter $\lambda$.

##### Example: Inferring behaviour from text-message data

Let's try to model a more interesting example, concerning text-message rates:

>  You are given a series of text-message counts from a user of your system. The data, plotted over time, appears in the graph below. You are curious if the user's text-messaging habits changed over time, either gradually or suddenly. How can you model this? (This is in fact my own text-message data. Judge my popularity as you wish.)

```
figsize( 12, 3.5 )
count_data = np.loadtxt("data/txtdata.csv")
n_count_data = len(count_data)
plt.bar( np.arange( n_count_data ), count_data, color ="#348ABD"  )
plt.xlabel( "Time (days)")
plt.ylabel("count of text-msgs received")
plt.title("Did the user's texting habits change over time?")
plt.xlim( 0, n_count_data );
```

Before we begin, with respect to the plot above, would you say there was a change in behaviour
during the time period?

How can we start to model this? Well, as I conveniently already introduced, a Poisson random variable would be a very appropriate model for this *count* data. Denoting day $i$'s text-message count by $C_i$,

$$ C_i \sim \text{Poisson}(\lambda)  $$

We are not sure about what the $\lambda$ parameter is though. Looking at the chart above, it appears that the rate might become higher at some later date, which is equivalently saying the parameter $\lambda$ increases at some later date (recall a higher $\lambda$ means more probability on larger outcomes, that is, higher probability of many texts.).

How can we mathematically represent this? We can think, that at some later date (call it $\tau$), the parameter $\lambda$ suddenly jumps to a higher value. So we create two $\lambda$ parameters, one for behaviour before the $\tau$, and one for behaviour after. In literature, a sudden transition like this would be called a *switchpoint*:

$$
\lambda =
\begin{cases}
\lambda_1  & \text{if } t \lt \tau \cr
\lambda_2 & \text{if } t \ge \tau
\end{cases}
$$

 If, in reality, no sudden change occurred and indeed $\lambda_1 = \lambda_2$, the $\lambda$'s posterior distributions should look about equal.

We are interested in inferring the unknown $\lambda$s. To use Bayesian inference, we need to assign prior probabilities to the different possible values of $\lambda$. What would be good prior probability distributions for $\lambda_1$ and $\lambda_2$? Recall that $\lambda_i, \; i=1,2,$ can be any positive number. The *exponential* random variable has a density function for any positive number. This would be a good choice to model $\lambda_i$. But, we need a parameter for this exponential distribution: call it $\alpha$.

\begin{align}
&\lambda_1 \sim \text{Exp}( \alpha ) \\\
&\lambda_2 \sim \text{Exp}( \alpha )
\end{align}

$\alpha$ is called a *hyper-parameter*, or a *parent-variable*, literally a parameter that influences other parameters. The influence is not too strong, so we can choose $\alpha$ liberally.  A good rule of thumb is to set the exponential parameter equal to the inverse of the average of the count data, since we're modeling $\\lambda$ using an Exponential distribution we can use the expected value identity shown earlier to get:

$$\frac{1}{N}\sum_{i=0}^N \;C_i \approx E[\; \lambda \; |\; \alpha ] = \frac{1}{\alpha}$$

Alternatively, and something I encourage the reader to try, is to have two priors: one for each $\lambda_i$; creating two exponential distributions with different $\alpha$ values reflects a prior belief that the rate changed after some period.

What about $\tau$? Well, due to the randomness, it is too difficult to pick out when $\tau$ might have occurred. Instead, we can assign an *uniform prior belief* to every possible day. This is equivalent to saying

\begin{align}
& \tau \sim \text{DiscreteUniform(1,70) }\\\\
& \Rightarrow P( \tau = k ) = \frac{1}{70}
\end{align}

So after all this, what does our overall prior for the unknown variables look like? Frankly, *it doesn't matter*. What we should understand is that it would be an ugly, complicated, mess involving symbols only a mathematician would love. And things would only get uglier the more complicated our models become. Regardless, all we really care about is the posterior distribution. We next turn to PyMC, a Python library for performing Bayesian analysis, that is agnostic to the mathematical monster we have created.

Introducing our first hammer: PyMC
-----

PyMC is a Python library for programming Bayesian analysis [3]. It is a fast, well-maintained library. The only unfortunate part is that documentation can be lacking in areas, especially the bridge between beginner to hacker. One of this book's main goals is to solve that problem, and also to demonstrate why PyMC is so cool.

We will model the above problem using the PyMC library. This type of programming is called *probabilistic programming*, an unfortunate misnomer that invokes ideas of randomly-generated code and has likely confused and frightened users away from this field. The code is not random. The title is given because we create probability models using programming variables as the model's components, that is, model components are first-class primitives in this framework.

B. Cronin [5] has a very motivating description of probabilistic programming:

>   Another way of thinking about this: unlike a traditional program, which only runs in the forward directions, a probabilistic program is run in both the forward and backward direction. It runs forward to compute the consequences of the assumptions it contains about the world (i.e., the model space it represents), but it also runs backward from the data to constrain the possible explanations. In practice, many probabilistic programming systems will cleverly interleave these forward and backward operations to efficiently home in on the best explanations.

Due to its poorly understood title, I'll refrain from using the name *probabilistic programming*. Instead, I'll simply use *programming*, as that is what it really is.

The PyMC code is easy to follow along: the only novel thing should be the syntax, and I will interrupt the code to explain sections. Simply remember we are representing the model's components ($\tau, \lambda_1, \lambda_2$ ) as variables:

```
import pymc as mc

n = count_data.shape[0]

alpha = 1.0/count_data.mean() #recall count_data is
                              #the variable that holds our txt counts

lambda_1 = mc.Exponential( "lambda_1",  alpha )
lambda_2 = mc.Exponential( "lambda_2", alpha )

tau = mc.DiscreteUniform( "tau", lower = 0, upper = n )
```

In the above code, we create the PyMC variables corresponding to $\lambda_1, \; \lambda_2$. We assign them to PyMC's *stochastic variables*, called stochastic variables because they are treated by the backend as random number generators. We can test this by calling their built-in `random()` method.

```
print "Random output:", tau.random(),tau.random(), tau.random()
```

    Random output: 55 42 41

```
@mc.deterministic
def lambda_( tau = tau, lambda_1 = lambda_1, lambda_2 = lambda_2 ):
    out = np.zeros( n )
    out[:tau] = lambda_1 #lambda before tau is lambda1
    out[tau:] = lambda_2 #lambda after tau is lambda2
    return out
```

This code is creating a new function `lambda_`, but really we think of it as a random variable: the random variable $\lambda$ from above. Note that because `lambda_1`, `lambda_2` and `tau` are random, `lambda_` will be random. We are **not** fixing any variables yet. The `@mc.deterministic` is a decorator to tell PyMC that this is a deterministic function, i.e., if the arguments were deterministic (which they are not), the output would be deterministic as well.

```
observation = mc.Poisson( "obs", lambda_, value = count_data, observed = True)

model = mc.Model( [observation, lambda_1, lambda_2, tau] )
```

The variable `observation` combines our data, `count_data`, with our proposed data-generation scheme, given by the variable `lambda_`, through the `value` keyword. We also set `observed = True` to tell PyMC that this should stay fixed in our analysis. Finally, PyMC wants us to collect all the variables of interest and create a `Model` instance out of them. This makes our life easier when we try to retrieve the results.

The below code will be explained in the Chapter 3, but this is where our results come from. One can think of it as a *learning* step. The machinery being employed is called *Monte Carlo Markov Chains* (which I delay explaining until Chapter 3). It returns thousands of random variables from the posterior distributions of $\lambda_1, \lambda_2$ and $\tau$. We can plot a histogram of the random variables to see what the posterior distribution looks like. Below, we collect the samples (called *traces* in MCMC literature) in histograms.

```
### Myserious code to be explained later.
mcmc = mc.MCMC(model)
mcmc.sample( 20000, 5000, 1 )
```

    [****************100%******************]  20000 of 20000 complete

```
lambda_1_samples = mcmc.trace( 'lambda_1' )[:]
lambda_2_samples = mcmc.trace( 'lambda_2' )[:]
tau_samples = mcmc.trace( 'tau' )[:]
```

```
figsize(12.5, 10)
#histogram of the samples:

ax = plt.subplot(311)
ax.set_autoscaley_on(False)

plt.hist( lambda_1_samples, histtype='stepfilled', bins = 32, alpha = 0.85,
        label = "posterior of $\lambda_1$", color = "#A60628",normed = True )
plt.legend(loc = "upper left")
plt.title(r"Posterior distributions of the variables $\lambda_1,\;\lambda_2,\;\tau$")
plt.xlim([15,30])
plt.xlabel("$\lambda$ value")
plt.ylabel("probability")

ax = plt.subplot(312)
ax.set_autoscaley_on(False)

plt.hist( lambda_2_samples,histtype='stepfilled', bins = 35, alpha = 0.85,
          label = "posterior of $\lambda_2$",color="#7A68A6", normed = True )
plt.legend(loc = "upper left")
plt.xlim([15,30])
plt.xlabel("$\lambda$ value")
plt.ylabel("probability")

plt.subplot(313)

w = 1.0/ tau_samples.shape[0] * np.ones_like( tau_samples )
plt.hist( tau_samples, bins = n_count_data, alpha = 1,
         label = r"posterior of $\tau$",
         color="#467821", weights=w, rwidth =1. )

plt.legend(loc = "upper left");
plt.ylim([0,.75])
plt.xlim([35, len(count_data)-20])
plt.xlabel("days")
plt.ylabel("probability");
```

### Interpretation

Recall that the Bayesian methodology returns a *distribution*, hence we now have distributions to describe the unknown $\lambda$'s and $\tau$. What have we gained? Immediately we can see the uncertainty in our estimates: the more variance in the distribution, the less certain our posterior belief should be. We can also say what a plausible value for the parameters might be: $\lambda_1$ is around 18 and $\lambda_2$ is around 23. What other observations can you make? Look at the data again, do these seem reasonable? The distributions of the two $\\lambda$s are positioned very differently, indicating that it's likely there was a change in the user's text-message behaviour.

Also notice that the posterior distributions for the $\lambda$'s do not look like any exponential distributions, though we originally started modelling with exponential random variables. They are really not anything we recognize. But this is OK. This is one of the benefits of taking a computational point-of-view. If we had instead done this mathematically, we would have been stuck with a very analytically intractable (and messy) distribution. Via computations, we are agnostic to the tractability.

Our analysis also returned a distribution for what $\tau$ might be. Its posterior distribution looks a little different from the other two because it is a discrete random variable, hence it doesn't assign probabilities to internals. We can see that near day 45, there was a 50% chance the users behaviour changed. Had no change occurred, or the change been gradual over time, the posterior distribution of $\tau$ would have been more spread out, reflecting that many values are likely candidates for $\tau$. On the contrary, it is very peaked.

###Why would I want samples from the posterior, anyways?

We will deal with this question for the remainder of the book, and it is an understatement to say we can perform amazingly useful things. For now, let's end this chapter with one more example. We'll use the posterior samples to answer the following question: what is the expected number of texts at day $t, \; 0 \le t \le70$? Recall that the expected value of a Poisson is equal to its parameter $\lambda$, then the question is equivalent to *what is the expected value of $\lambda$ at time $t$*?

In the code below, we are calculating the following: Let $i$ index samples from the posterior distributions. Given a day $t$, we average over all possible $\lambda_i$ for that day $t$, using $\lambda_i = \lambda_{1,i}$ if $t \lt \tau_i$ (that is, if the behaviour change hadn't occurred yet), else we use $\lambda_i = \lambda_{2,i}$.

___________________

```
figsize( 12.5, 4)
# tau_samples, lambda_1_samples, lambda_2_samples contain
# N samples from the corresponding posterior distribution
N = tau_samples.shape[0]
expected_texts_per_day = np.zeros(n_count_data)
for  day in range(0, n_count_data):
    # ix is a bool index of all tau samples corresponding to
    # the switchpoint occurring prior to value of 'day'
    ix = day < tau_samples
    # Each posterior sample corresponds to a value for tau.
    # for each day, that value of tau indicates whether we're "before" (in the lambda1 "regime")
    # or "after" (in the lambda2 "regime") the switchpoint.
    # by taking the posterior sample of lambda1/2 accordingly, we can average
    # over all samples to get an expected value for lambda on that day.
    # As explained, the "message count" random variable is Poisson distributed,
    # and therefore lambda (the poisson parameter) is the expected value of "message count"
    expected_texts_per_day[day] = (lambda_1_samples[ix].sum()
                                    + lambda_2_samples[~ix].sum() ) /N

plt.plot( range( n_count_data), expected_texts_per_day, lw =4, color = "#E24A33" )
plt.xlim( 0, n_count_data )
plt.xlabel( "Day" )
plt.ylabel( "Expected # text-messages" )
plt.title( "Expected number of text-messages received")
#plt.ylim( 0, 35 )
plt.bar( np.arange( len(count_data) ), count_data, color ="#348ABD", alpha = 0.5,
            label="observed texts per day")

plt.legend(loc="upper left");
```

Our analysis shows strong support for believing the user's behavior did change ($\lambda_1$ would have been close in value to $\lambda_2$ had this not been true), and the change was sudden rather then gradual (demonstrated by $\tau$'s strongly peaked posterior distribution). We can speculate what might have caused this: a cheaper text-message rate, a recent weather-2-text subscription, or a new relationship. (The 45th day corresponds to Christmas, and I moved away to Toronto the next month leaving a girlfriend behind.)

##### Exercises

1\.  Using `lambda_1_samples` and `lambda_2_samples`, what is the mean of the posterior distributions of $\lambda_1$ and $\lambda_2$?

```
#type your code here.
```

2\.  What is the expected percentage increase in text-message rates? `hint:` compute the mean of `lambda_1_samples/lambda_2_samples`. Note that quantity is very different from `lambda_1_samples.mean()/lambda_2_samples.mean()`.

```
#type your code here.
```

3\. Looking at the posterior distribution graph of $\tau$, why do you think there is a small number of posterior $\tau$ samples near 0? `hint:` Look at the data again.

4\. What is the mean of $\lambda_1$ **given** we know $\tau$ is less than 45.  That is, suppose we have new information as we know for certain that the change in behaviour occurred before day 45. What is the expected value of $\lambda_1$ now? (You do not need to redo the PyMC part, just consider all instances where `tau_trace<45`. )

```
#type your code here.
```

### References

-  [1] Gelman, Andrew. N.p.. Web. 22 Jan 2013. <http://andrewgelman.com/2005/07/n_is_never_larg/>.
-  [2] Norvig, Peter. 2009. [*The Unreasonable Effectiveness of Data*](http://www.csee.wvu.edu/~gidoretto/courses/2011-fall-cp/reading/TheUnreasonable EffectivenessofData_IEEE_IS2009.pdf).
- [3] Patil, A., D. Huard and C.J. Fonnesbeck. 2010.
PyMC: Bayesian Stochastic Modelling in Python. Journal of Statistical
Software, 35(4), pp. 1-81.
- [4] Jimmy Lin and Alek Kolcz. Large-Scale Machine Learning at Twitter. Proceedings of the 2012 ACM SIGMOD International Conference on Management of Data (SIGMOD 2012), pages 793-804, May 2012, Scottsdale, Arizona.
- [5] Cronin, Beau. "Why Probabilistic Programming Matters." 24 Mar 2013. Google, Online Posting to Google . Web. 24 Mar. 2013. <https://plus.google.com/u/0/107971134877020469960/posts/KpeRdJKR6Z1>.

```
from IPython.core.display import HTML
def css_styling():
    styles = open("../styles/custom.css", "r").read()
    return HTML(styles)
css_styling()
```

<style>
    @font-face {
        font-family: "Computer Modern";
        src: url('http://mirrors.ctan.org/fonts/cm-unicode/fonts/otf/cmunss.otf');
    }
    div.cell{
        width:800px;
        margin-left:auto;
        margin-right:auto;
    }
    h1 {
        font-family: Helvetica, serif;
    }
    h4{
        margin-top:12px;
        margin-bottom: 3px;
       }
    div.text_cell_render{
        font-family: Computer Modern, "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
        line-height: 145%;
        font-size: 120%;
        width:800px;
        margin-left:auto;
        margin-right:auto;
    }
    .CodeMirror{
            font-family: "Source Code Pro", source-code-pro,Consolas, monospace;
    }
    .prompt{
        display: None;
    }
    .text_cell_render h5 {
        font-weight: 300;
        font-size: 16pt;
        color: #4057A1;
        font-style: italic;
        margin-bottom: .5em;
        margin-top: 0.5em;
        display: block;
    }

    .warning{
        color: rgb( 240, 20, 20 )
        }

</style>

```

```


## LMA source files

Most of the older LMA source files have filenames like `LYLOUT_20211013_000000_0600.dat.gz`.

Newer ones look like `WTLMA_2011_211013_102700_0060.dat.gz`.

In the newer files, `LYLOUT` (which was shared by all networks) is replaced with a network identifier, here `WTLMA_2011`, for the West Texas LMA that was established in 2011. All files end with `yyyymmdd_HHMMSS_duration.dat.gz`. The start time of the file is `yyyymmdd_HHMMSS`, and `duration` is the total length of the file in seconds.

They are compressed (`.gz`) plain text files - if you unzip them you can look at them with any text editor.

Realtime data files are usually one minute in length, though sometiems they are also provided as bundles of hourly data. Postprocessed data files are almost always ten minutes long.

### Headers of LMA postprocessed data.

Main sections:
- `Analysis program:` is the command used to process this data file.
- The next few lines are information about the LMA network read from the `.loc` or `.gps` file provided to the processing program, and other information about the processing settings used.
- The `Station information` table provides the location (here, truncated for privacy)  and receive channel (Ch. 3 is 60-66 MHz) of each station.
- The `Station data` table gives the data collection mode of the station. Here we see an 80 µs collection window was used, that there was an assumed 70 ns GPS timing error, the number and fraction of sources to which each station contributed, a power metric relative to the median (I think), and  whether that station was active and used in processing this data file.
- The `Station mask order` tells us which station corresponds to which bit in the station mask. We'll explain this below.
- Finally, we have a description of the data format for the VHF sources (here, called events), with a descriptive name for each column and its the data format, and the total event count. These descriptions are not always correct, as you can see for the realtime data file!

**Postprocssed data header** from 2021-06-27, 0200-0210 UTC - ten minutes of data.
Lightning Mapping Array analyzed data
Analysis program: /data/lma_realtime/new/lma_analysis-10.14.9R -d 20210627 -t 020000 -s 600 -g /data/lma_realtime/new/wt.gps -a -n 5 -o /data/rtlma/processed_data/2021/Jun/27/ -q -x 5.00 -y 500.00
Analysis program version: 10.14.9R
File created: Thu Sep 16 03:34:46 2021
Data start time: 06/27/21 02:00:00
Number of seconds analyzed: 600
Location: WTLMA_2011
Coordinate center (lat,lon,alt): 33.6069680 -101.8226250 984.00
Coordinate frame: cartesian
Maximum diameter of LMA (km): 79.743
Maximum light-time across LMA (ns): 266047
Number of stations: 13
Number of active stations: 8
Active stations: G W B N L P H X
Minimum number of stations per solution: 5
Maximum reduced chi-squared: 5.00
Maximum number of chi-squared iterations: 20
Station information: id, name, lat(d), lon(d), alt(m), delay(ns), board_rev, rec_ch
Sta_info: E  Estac              33.6 -101.8   984.00   26 3  3
Sta_info: G  Idalo              33.7 -101.6   992.00   26 3  3
Sta_info: W  Llano              33.4 -101.7   956.85   26 3  3
Sta_info: B  Biggin             33.7 -102.0  1007.59   26 3  3
Sta_info: N  Newdl              33.7 -101.8   998.45   26 3  3
Sta_info: O  Reese              33.5 -102.0  1018.00   26 3  3
Sta_info: R  Roosevelt          33.5 -101.6   960.00   26 3  3
Sta_info: L  Loren              33.6 -101.5   956.00   26 3  3
Sta_info: P  Peter              33.8 -101.6   978.00   26 3  3
Sta_info: A  Abern              33.9 -101.8  1022.23   26 3  3
Sta_info: H  Wolff              33.4 -102.0   993.51   26 3  3
Sta_info: X  Level              33.5 -102.3  1049.01   26 3  3
Sta_info: T  ReeseTower         33.6 -102.0  1019.00   26 3  3
Station data: id, name, win(us), dec_win(us), data_ver, rms_error(ns), sources, %, <P/P_m>, active
Sta_data: E  Estac                0     0   70        0   0.0  0.00  NA
Sta_data: G  Idalo               80    12   70   515907  88.0  0.75   A
Sta_data: W  Llano               80    12   70   463829  79.2  0.03   A
Sta_data: B  Biggin              80    12   70   474843  81.0  1.77   A
Sta_data: N  Newdl               80    12   70   523811  89.4  0.85   A
Sta_data: O  Reese                0     0   70        0   0.0  0.00  NA
Sta_data: R  Roosevelt            0     0   70        0   0.0  0.00  NA
Sta_data: L  Loren               80    12   70   320263  54.7  2.33   A
Sta_data: P  Peter               80    12   70   497376  84.9  2.21   A
Sta_data: A  Abern                0     0   70        0   0.0  0.00  NA
Sta_data: H  Wolff               80    12   70   390070  66.6  0.66   A
Sta_data: X  Level               80    12   70    43247   7.4  0.00   A
Sta_data: T  ReeseTower           0     0   70        0   0.0  0.00  NA
Metric file version: 4
Station mask order: TXHAPLRONBWGE
Data: time (UT sec of day), lat, lon, alt(m), reduced chi^2, P(dBW), mask
Data format: 15.9f 12.8f 13.8f 9.2f 6.2f 5.1f 6x
Number of events: 585980
*** data ***
 7195.563227082  14.42079200 -168.11020038 1471087992.23 230.40 100.1 0x011e
 7198.034285095   1.85676802 -166.66390846 616695433.21 336.78  93.6 0x050e
 7199.534259710  73.62739777   92.92428877 154306312.18  85.80  82.2 0x019c
 7199.999970628  33.57516955 -101.85614830  13424.97 101.96  -1.4 0x0516
 7200.000295524  34.00685344 -101.79561170   6858.94   0.17  11.0 0x009e
 7200.000769921  33.98258103 -101.79108175   6512.81   0.31   7.9 0x0c16
 7200.000901130  34.00999875 -101.81978857   7349.40   0.37   7.6 0x011e
 7200.001103478  34.19873867 -101.73348211  27670.57   3.82  14.7 0x050e
 7200.001213632  33.77065089 -102.07323840   9979.92   2.27  14.5 0x0598
 7200.001485129  34.05024204 -101.78250330  13454.71   0.29  15.1 0x058c
**Realtime data header** from 2021-10-13 0400-0401 UTC - one minute of data.
Lightning Mapping Array analyzed data
Analysis program: /data/lma_realtime/new/lma_analysis-10.14.9RT -g /data/lma_realtime/new/wt.gps -n 5 -o /data/lma_realtime/out -x 5.00
Analysis program version: 10.14.9RT
File created: Wed Oct 13 04:01:02 2021
Data start time: 10/13/21 04:00:00
Number of seconds analyzed: 60
Location: WTLMA_2011
Coordinate center (lat,lon,alt): 33.6069680 -101.8226250 984.00
Coordinate frame: cartesian
Maximum diameter of LMA (km): 79.743
Maximum light-time across LMA (ns): 266047
Number of stations: 12
Number of active stations: 7
Active stations: W B N P A H X
Minimum number of stations per solution: 5
Maximum reduced chi-squared: 5.00
Maximum number of chi-squared iterations: 20
Station information: id, name, lat(d), lon(d), alt(m), delay(ns), board_rev, rec_ch
Sta_info: E  Estac              33.6  -101.8   984.00   26 3  3
Sta_info: G  Idalo              33.7  -101.6   992.00   26 3  3
Sta_info: W  Llano              33.4  -101.7   956.85   26 3  3
Sta_info: B  Biggin             33.7  -102.0  1007.59   26 3  3
Sta_info: N  Newdl              33.7  -101.8   998.45   26 3  3
Sta_info: O  Reese              33.5  -102.0  1018.00   26 3  3
Sta_info: R  Roosevelt          33.5  -101.6   960.00   26 3  3
Sta_info: L  Loren              33.6  -101.5   956.00   26 3  3
Sta_info: P  Peter              33.8  -101.6   978.00   26 3  3
Sta_info: A  Abern              33.9  -101.8  1022.23   26 3  3
Sta_info: H  Wolff              33.4  -102.0   993.51   26 3  3
Sta_info: X  Level              33.5  -102.3  1049.01   26 3  3
Station data: id, name, win(us), dec_win(us), data_ver, rms_error(ns), sources, %, <P/P_m>, active
Sta_data: E  Estac                0     0   70        0   0.0  0.00  NA
Sta_data: G  Idalo               80    12   70       74 7400.0  1.07  NA
Sta_data: W  Llano               80    12   70        2 200.0  0.34   A
Sta_data: B  Biggin              80    12   70        3 300.0  0.22   A
Sta_data: N  Newdl               80    12   70       76 7600.0  0.35   A
Sta_data: O  Reese                0     0   70        0   0.0  0.00  NA
Sta_data: R  Roosevelt            0     0   70        0   0.0  0.00  NA
Sta_data: L  Loren                0     0   70        0   0.0  0.00  NA
Sta_data: P  Peter               80    12   70       77 7700.0  1.58   A
Sta_data: A  Abern               80    12   70       76 7600.0  3.99   A
Sta_data: H  Wolff               80    12   70       76 7600.0  0.31   A
Sta_data: X  Level               80    12   70        2 200.0  0.09   A
Metric file version: 4
Station mask order: XHAPLRONBWGE
Data: time (UT sec of day), lat, lon, alt(m), reduced chi^2, P(dBW), mask
Data format: 15.9f 12.8f 13.8f 9.2f 6.2f 5.1f 5x
Number of events: 1
*** data ***
14402.294258784  33.68914553 -102.11318221  32320.04   3.96  -8.2 0xf08
14406.018238618  33.66219201 -102.05494124  37331.34   0.67   5.0 0x718
14429.547782698  34.24702550 -101.74849670   7692.76   0.13  10.6 0x712
14429.556551814  34.24626004 -101.75420033   7793.37   0.02  21.9 0x712
14429.558081952  34.24751434 -101.75747915   8816.25   2.03  10.2 0x712

How do we tell the difference between the file types? Look at the `lma_analysis` line: the program version ending in `RT` indicates realtime, while the postprocessing ends in `R`, for reasons I don't understand. The path to the output filename location (`-o`) also gives a clue about where the data file was first saved, which hopefully was on a somewhat informative path on your data processing server.

## Interpreting the event data columns

The time and location columns in the data file above are self-explanatory, though it is good to know they are with respect to the WGS84 ellipsoid. The event power, in dBW at the source, is also provided.

The station mask column is a [hexadecimal number](https://en.wikipedia.org/wiki/Hexadecimal), where each digit after the `0x` represents a value between 0-15. Let's look at how to interpret `0xf08`.

```python
# Convert hexadecimal (base-16) to a decimal (base-10) integer
hexmask = '0xf09'
number = int(hexmask, 16)
print("Hex {0} is decimal integer {1}".format(hexmask, number))

# Print the integer as a decimal, and as binary, with leading zeroes and 16 bits (016b).
print("Integer {0} is binary {0:016b}".format(number))
```

    Hex 0xf09 is decimal integer 3849
    Integer 3849 is binary 0000111100001001

We see that `0xf09` converts to this binary string corresponding to the station location order from the header:

```
0000111100001001
    XHAPLRONBWGE
```

so stations X, H, A, P, B, and E contributed to this solution. If we sum the bits in the station mask, we find the number of contributing stations was 6. This is above the minimum required for a solution (5).

**The number of contributing staitons is an important parameter that lets us control the amount of noise in our science analyses.**

For a fullly operational network a minimum of 6 contributing stations is a good starting number, but values of 5 or 7 can be useful.

Noise is primarily caused by false correlations produced by random, local VHF sources at several stations that happen to correlate with each other. More stations in a network means a greater chance of false corelation, so larger LMA networks tend to need a minimum higher station count to keep noise in check.

**The other primary quality control parameter is the reduced `chi^2` value.** The processing requires that all sources have $\chi^2 < 5$.

(If you see values larger than 5 in a data file, a second pass has been used to restore some very high power sources that might be a special class of discharge called "narrow bipolar events". The post-processed header above includes `-y 500.00`, so a second pass was done for that data file, up to $\chi^2 < 500$.)

$\chi^2$ is a measure of the goodness of fit of the solutions. Specififally, it is the [$\chi^2$ statistic](https://mathworld.wolfram.com/Chi-SquaredDistribution.html) of the normalized squared timing errors. Using the notation of [Thomas et al. (2004)](10.1029/2004JD004549), eq. A2,

\begin{equation}
\Large\chi^2 = \Large\sum_{i=1}^N \frac{(t_i^\mathrm{obs} - t_i^\mathrm{fit})^2}{\Delta t_\mathrm{rms}^2},
\end{equation}

where $t_i^\mathrm{obs}$ is the observed arrival time of the source at each station, and $t_i^\mathrm{fit}$ the predicted arrival time of each source (traveling at the speed of light) at each station. $\Delta t_\mathrm{rms}$ is the expected (root mean square) normalized timing error assumed in the processing, i.e., 70 ns for the two data files above.

The actual value in the file is the **reduced $\chi^2$**,

\begin{equation}
\chi_{\nu}^2 = \frac{\chi^2}{N - 4}
\end{equation}

which has been further normalized by the number of degrees of freedom $\nu = N - 4$, where $N$ is the number of contributing stations and 4 is the number of retrieved paramters for the source location $(x,y,z,t)$.

Using these equations, we can convert the data file's $\chi_{\nu}^2$ value into the actual timing errors, and/or calculate the true \chi_{\nu}^2 for the actual GPS timing noise, which is typically less than 70 ns.

([Thomas et al. (2004)](10.1029/2004JD004549) shows how the timing errors relate to range, azimuth, and elevation errors, and how to determine $\Delta t_\mathrm{rms}$ for any data file.)

Practically speaking, we usualy don't calculate the corrected $\chi_\nu^2$ unless we care about converting the timing errors into location errors.  Instead, we simply use the file's $\chi_{\nu}^2$ and reduce our maximum chi-sq until we're satisfied we've removed most noise.

When [working with data from some day for the first time](./FirstLMAplots.ipynb), it is useful to experiment with a minimum number of stations of 5, 6, and 7, and reduced chi-squared values of 1.0 and 5.0, since the best setting for that day depends on the number of active stations and the radio noise in the ambient environment on that day. You will observe that there is a tradeoff between removing noise and removing detail in lightning channels. The balance point is a judgment call, but should always be reported in publications using LMA data.

Before we [move on to actually trying to filter and plot some data ourselves](./FirstLMAplots.ipynb), let's use the cell below to look at the header of a file we'll work with later today. You might need to adjust `n_lines` to see more of the header.

```python
n_lines = 100
filename = '/data/Houston/realtime-tracer/LYLOUT_200524_210000_0600.dat.gz'

import gzip
with gzip.open(filename, 'rt', encoding='utf8') as lmafile:
    header_lines = [lmafile.readline() for i in range(n_lines)]
for line in header_lines:
    print(line, end='')
```

    New Mexico Tech Lightning Mapping Array - analyzed data
    Analysis program: /data1/hlma_tamu/lma_analysis -d 20200524 -t 210000 -s 600 -l /data1/hlma_tamu/hstnA.loc -o /data1/hlma_data/processed/080us_data/0600/nomdl//2020/05/200524 -x 5.00 -y 500.00
    Analysis program version: 10.11.7R
    File created: Mon May 25 00:23:04 2020
    Data start time: 05/24/20 21:00:00
    Number of seconds analyzed: 600
    Location: HSTN LMA 2012
    Coordinate center (lat,lon,alt): 29.7600000 -95.3700000 -200.00
    Coordinate frame: cartesian
    Maximum diameter of LMA (km): 205.007
    Maximum light-time across LMA (ns): 683965
    Number of stations: 13
    Number of active stations: 7
    Active stations: A B I J K L M
    Minimum number of stations per solution: 6
    Maximum reduced chi-squared: 5.00
    Maximum number of chi-squared iterations: 20
    Station information: id, name, lat(d), lon(d), alt(m), delay(ns), board_rev, rec_ch
    Sta_info: A  Cy-Fair ISD        29.9392583  -95.6464869    24.31   45 3  3
    Sta_info: B  Williams Airport   30.1574342  -95.3209639    19.35   45 3  3
    Sta_info: C  Johnson Space Center   29.5670202  -95.0984633    -2.93   45 3  3
    Sta_info: D  Sugarland          29.6196458  -95.6576139     3.06   45 3  3
    Sta_info: E  TAMU 1             30.6461624  -96.2979071    75.82   45 3  2
    Sta_info: F  Houston SW Airport   29.5050035  -95.4759368     6.89   45 3  3
    Sta_info: G  Addicks            29.7679573  -95.6452786    15.23   45 3  3
    Sta_info: H  Houston Raceway    29.7913451  -94.8828558    -5.65   45 3  3
    Sta_info: I  TAMU 2             30.6462000  -96.2979000    69.02   45 3  3
    Sta_info: J  Lone Star College   30.0019908  -95.3840236     6.76   45 3  3
    Sta_info: K  Alvin              29.4407042  -95.2733397    -5.24   45 3  3
    Sta_info: L  May                30.0581250  -95.0614192     1.39   45 3  3
    Sta_info: M  Galveston          29.3159000  -94.8220000    -2.99   45 3  3
    Station data: id, name, win(us), dec_win(us), data_ver, rms_error(ns), sources, %, <P/P_m>, active
    Sta_data: A  Cy-Fair ISD         80    10   70   118447  99.3  2.07   A
    Sta_data: B  Williams Airport    80    10   70   118433  99.3  2.29   A
    Sta_data: C  Johnson Space Center     0     0   70        0   0.0  0.00  NA
    Sta_data: D  Sugarland            0     0   70        0   0.0  0.00  NA
    Sta_data: E  TAMU 1               0     0   70        0   0.0  0.00  NA
    Sta_data: F  Houston SW Airport     0     0   70        0   0.0  0.00  NA
    Sta_data: G  Addicks              0     0   70        0   0.0  0.00  NA
    Sta_data: H  Houston Raceway      0     0   70        0   0.0  0.00  NA
    Sta_data: I  TAMU 2              80    10   70   118061  99.0  0.08   A
    Sta_data: J  Lone Star College    80    10   70   118294  99.2  0.30   A
    Sta_data: K  Alvin               80    10   70   117986  98.9  0.78   A
    Sta_data: L  May                 80    10   70   110846  92.9  2.13   A
    Sta_data: M  Galveston           80    10   70    14116  11.8 76.22   A
    Metric file version: 4
    Station mask order: MLKJIHGFEDCBA
    Data: time (UT sec of day), lat, lon, alt(m), reduced chi^2, P(dBW), mask
    Data format: 15.9f 12.8f 13.8f 9.2f 6.2f 5.1f 6x
    Number of events: 119290
    *** data ***
    75591.978874007  79.70932923 -114.48340374 2406689178.91  35.72 101.7 0x1703
    75599.998664584  27.39779476  -95.62892200 719865.17 166.77  30.3 0x1703
    75600.000080056  30.51557585  -95.56277434   9948.14 149.81  12.0 0x0f03
    75600.000367376  30.88925893  -95.30721212  11633.74 314.10  23.7 0x0f03
    75600.000434196  30.05190243  -95.79910575  33037.95   3.70   8.5 0x1703
    75600.001399791  30.82301277  -95.47161575   6411.17   0.14  16.4 0x0f03
    75600.001552058  30.78454293  -95.30852548  10396.54   0.14  15.8 0x0f03
    75600.001748370  30.71511685  -95.64580199    742.16 154.69  14.1 0x0f03
    75600.002204027  30.49020057  -95.51679219   7324.00   4.76  10.5 0x0f03
    75600.003609747  29.91724127  -95.17903970  13222.17  52.06   4.0 0x0f03
    75600.003954346  30.78271680  -95.30956792  10765.62   0.08  19.2 0x0f03
    75600.004041880  30.82071122  -95.29332307   7274.72   5.15  16.8 0x0f03
    75600.005431992  29.93996735  -96.30764088  13947.72 160.35  20.9 0x0f03
    75600.005882026  30.48913577  -95.51506485   8307.87   0.02  12.6 0x0f03
    75600.006463519  15.49003757  -98.65527996 3505839.60 135.01  45.3 0x1b03
    75600.008114909  30.23230682  -95.69142961  37035.82 299.60  10.0 0x1703
    75600.008193535  29.96158364  -96.39246591  17331.83 118.72  22.7 0x0f03
    75600.009615840  30.51119988  -95.58075716   8579.13   0.10  19.4 0x0f03
    75600.009695027  30.51200176  -95.58121006   8126.00   0.37  11.1 0x0f03
    75600.010946557  29.95254677  -96.39864220  10102.00   0.14  21.4 0x0f03
    75600.012435197  30.77913572  -95.33296927   6726.34   0.09  12.3 0x0f03
    75600.012628815  30.49530217  -95.50177713   7867.36  18.08  10.5 0x0f03
    75600.013701366  30.51012676  -95.58451940   8477.86   0.18  14.7 0x0f03
    75600.013852652  29.91800885 -100.46163291 182057.84 145.30  24.7 0x1703
    75600.014096699  30.51108028  -95.58329245   8955.30   2.49  12.3 0x0f03
    75600.014530316  29.95579657  -96.39807772  13360.71   2.83  24.0 0x0f03
    75600.014733671  30.48676064  -95.51246549   7696.23   4.16  14.9 0x0f03
    75600.014849400  30.48388991  -95.51274343   8495.17  16.11  14.0 0x0f03
    75600.015756768  30.49476360  -95.50253507   8708.50   0.16  17.5 0x0f03
    75600.016415183  30.48380113  -95.51426141   8363.24   6.96  10.3 0x0f03
    75600.017501534  30.00980639  -96.34460249  14136.79 352.52   9.1 0x1703
    75600.017761630  30.51341646  -95.58546891   8601.91   0.39  13.3 0x0f03
    75600.020262247  41.55817024  -85.67353157 1975337.34  99.43  35.3 0x1703
    75600.020376910  29.96574530  -96.49436881   5043.18 180.18  21.5 0x0f03
    75600.020400010  30.46027205  -95.49275367   8241.02 148.68  19.1 0x0f03
    75600.020565633  29.95470580  -96.39262310  11576.86   0.08  21.8 0x0f03
    75600.021161321  30.49254865  -95.50437149   8834.57   0.60   9.4 0x0f03
    75600.021637111  30.49300121  -95.50419577   8783.24  18.30  15.9 0x0f03
    75600.021929961  30.53010627  -95.52304394   5435.84   0.09  11.0 0x0f03
    75600.024595259  29.97064879  -95.26012393  43638.48 170.37   6.6 0x1703
    75600.025243989  30.72271316  -95.39656696   7015.05   1.56   9.3 0x0f03
    75600.027739195  30.48166319  -95.50737724   7735.94   5.17  17.5 0x0f03
    75600.028721960  30.51964581  -95.58446590   8605.89   0.33  15.0 0x0f03
    75600.031864116  30.47716015  -95.50704139   8200.90   0.77  11.2 0x0f03
    75600.032694056  30.52458915  -95.58517353   8541.51   0.02  11.6 0x0f03
    75600.032812068  30.86507046  -95.31458893   5228.54  47.90  15.6 0x0f03
    75600.033274952  29.62603808  -95.57112845  29373.25 179.70   4.0 0x1703
    75600.033612308  30.07638288  -96.45165599 491638.76 177.56  19.8 0x1703
    75600.034853640  30.52693153  -95.58457205   8436.68   0.15   9.3 0x0f03

```python

```


-------------------------------------------------------------------------

 中学生の数学をパイソンで学ぶ(中1病)

 coding: utf-8
 published at: 2022-01-08

 MITlicense (c) 2022 DomZeroYunx(asdjod13ff@pm.me)
 転載の際は必ず著作表示を保持してください。

-------------------------------------------------------------------------

みんな大好きゲームを作りたい。けどついでにPythonで数学も進めてみよう！
まずは中学1年生からだよ。変数にまで日本語を使っているからわかりやすく書いていきたいですがなかなかうまくいきません。

[]: # Language: markdown
[]: # Path: cyu1.ipynb

# 正の数と負の数をコンソールで表示してみる

```python
# こいつらみんな整数
原点 = [0] # ０は自然数ではないけど整数
自然数 = [1,2,3,4,5,6,7,8,9] # 自然数であり整数
自然数にプラスがついても同じ = [+1,+2,+3,+4,+5,+6,+7,+8,+9] # プラスがついても同じ
負数 = [-1,-2,-3,-4,-5,-6,-7,-8,-9] # 自然数ではない

print("整数を表示" + str(負数) + str(原点) + str(自然数)) ## 整数を表示
print("自然数を表示します" + str(自然数))## 自然数を表示
print("自然数にプラスがついても同じを表示します" + str(自然数にプラスがついても同じ)) ## 自然数にプラスがついても同じ
print("負数を表示します" + str(負数)) ## 負数を表示
```

    整数を表示[-1, -2, -3, -4, -5, -6, -7, -8, -9][0][1, 2, 3, 4, 5, 6, 7, 8, 9]
    自然数を表示します[1, 2, 3, 4, 5, 6, 7, 8, 9]
    自然数にプラスがついても同じを表示します[1, 2, 3, 4, 5, 6, 7, 8, 9]
    負数を表示します[-1, -2, -3, -4, -5, -6, -7, -8, -9]

## 正の数と負の数を図にしてみる

```python
from numpy.random import *
import matplotlib
from matplotlib import pyplot as plt
import numpy as np
%matplotlib inline

# --- 正の数負の数の基礎 -----------------------------------------------------

原点 = [0]                                  # ０は自然数ではないけど整数
自然数 = [1,2,3,4,5,6,7,8,9,10]             # 自然数であり整数(+がついても同じ)
負数 = [-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]     # 自然数ではない

# ---------------------------------------------------------------------------

# ラベル用
fig, ax = plt.subplots()                 # 初期化
ax2 = ax.twinx()                         # 右側に表示

# 邪魔なラベルを消す
ax.get_xaxis().set_visible(False)     # x軸
plt.xticks([])                       # x軸のラベル
ax2.get_yaxis().set_visible(False)  # y軸
plt.yticks([])                     # y軸のラベル

# グラフの設定
plt.title("整数を表示",fontname="MS Gothic")                                # タイトル
ax.set_ylabel('負数     < 整数 >    正数',fontname="MS Gothic")             # 日本語で読みやすく
ax.plot(負数, color='red', linestyle='-', linewidth=0, label='負数')        # 負数のグラフは非表示にする
ax.plot(原点, color='blue', linestyle='-', linewidth=2, label='原点')       # 原点
ax.plot(自然数, color='green', linestyle='-', linewidth=0, label='自然数')  # 自然数のグラフは非表示にする
plt.quiver(0,10,scale=1,color='green')                                      # 棒グラフを表示するためベクトル
plt.quiver(0,-10,scale=1,color='red')                                       # 棒グラフを表示するためベクトル
ax.set_ylim(-10,10)                                                                 # y軸の小数点は切り捨てる
ax.set_yticks(np.arange(-10,10,1))                                                  # 1刻みで表示
ax.grid(True)                                                                       # グリッドを表示
ax.plot(0, 0, 'o', color='blue', markersize=10)                                        # 原点を表示
ax.text(0.3, -0.3, '原点: 0 (自然じゃない)',fontname="MS Gothic", fontsize=16)          # 原点のラベル
ax.text(1, -4, '負数: -1,-2,-3,-4,-5,-6,-7,-8,-9',fontname="MS Gothic", fontsize=16) # 負数のラベル
ax.text(1, 5, '正数: 1,2,3,4,5,6,7,8,9',fontname="MS Gothic", fontsize=16)            # 自然数のラベル
ax.text(1, 3, '正数(上と同じ): +1,+2,+3,+4,+5,+6,+7,+8,+9',fontname="MS Gothic", fontsize=12)  # +がついても同じのラベル
plt.show() # グラフを表示

```

0より大きい数は正の数です。
0より小さい数は負の数です。
0は正でも負でもない数です。

```python
from numpy.random import *
import matplotlib
from matplotlib import pyplot as plt
import numpy as np
%matplotlib inline

# plot全体の高さを指定
fig = plt.figure(figsize=(10,1)) #figsize=(width,height)

x = np.arange(-9,10,1)
y = np.zeros(len(x))#y軸は直線表示のみ
plt.yticks([])#y軸のラベルを非表示
plt.title("正の数、負の数",fontname="MS Gothic")#タイトルを設定
plt.xticks(np.arange(-9,10,1))#小数点以下は切り捨て整数のみ表示
plt.grid(True)

x = np.arange(-9,1,1)
y = np.zeros(len(x))
plt.plot(x,y,color='red',linestyle='-',linewidth=3)
plt.text(-8.5, 0, '負の数',fontname="MS Gothic", fontsize=16)

x = np.arange(0,10,1)
y = np.zeros(len(x))
plt.plot(x,y,color='green',linestyle='-',linewidth=3)
plt.text(8.5, 0, '正の数',fontname="MS Gothic", fontsize=16)

x = np.arange(0,0.1,1)
y = np.zeros(len(x))
plt.plot(x,y,color='blue',linestyle='-',linewidth=3)
plt.text(-0.5, 0, '原点',fontname="MS Gothic", fontsize=18)

plt.show()

```

赤い線が負の数です、0を含まない-1から-9の部分が赤くなりました。
原点と呼ばれる0はちょうど正と負の間です。0は正でも負でもありません。
緑の部分は0より大きい数です。これは正の数です。

- 原点より右が正の数
- 原点より左が負の数
- 原点の０は正でも負でもありません。

そして右に行くほど正の数が大きくなります。それはおこずかいが0円から9円のおこづかいになるようなものです。
そして左に行くほど負の数が大きくなります。それはおこずかいの9円が0円になるようなものです。酷い話ですね

## 原点からの計算方法（絶対値の計算方法）

```python
from numpy.random import *
import matplotlib
from matplotlib import pyplot as plt
import numpy as np
%matplotlib inline

# plot全体の高さを指定
fig = plt.figure(figsize=(10,1)) #figsize=(width,height)

# 0から4までの自然数を表示
x = np.arange(0.1,4,0.1)
y = np.zeros(len(x))
plt.plot(x,y,color='green',linestyle='-',linewidth=6)
plt.text(0, 0, '原点0から数える',fontname="MS Gothic", fontsize=16)

x = np.arange(-9,9,1)
y = np.zeros(len(x))

x = np.arange(-9,10,1)
y = np.zeros(len(x))#y軸は直線表示のみ
plt.yticks([])#y軸のラベルを非表示
plt.title("原点からの計算で絶対値の距離を求める",fontname="MS Gothic")#タイトルを設定
plt.xticks(np.arange(-9,10,1))#小数点以下は切り捨て整数のみ表示
plt.grid(True)

plt.show()
```

0は原点と覚えましたね。

> 0からの距離からの決めた数までの距離をを 絶対値 と呼びます。
この図の場合には0から数えて 4 ですね？つまり 絶対値は 4 になります

### 次の図で絶対値がいくつになるか考えてみてください。

```python
from numpy.random import *
import matplotlib
from matplotlib import pyplot as plt
import numpy as np
%matplotlib inline

# plot全体の高さを指定
fig = plt.figure(figsize=(10,1)) #figsize=(width,height)

# 0から4までの自然数を表示
x = np.arange(0.1,6,0.1) #グラフの軸合わせで適当に加算
y = np.zeros(len(x))
plt.plot(x,y,color='green',linestyle='-',linewidth=6)
plt.text(0, 0, '原点0から数える',fontname="MS Gothic", fontsize=16)

x = np.arange(-9,9,1)
y = np.zeros(len(x))

x = np.arange(-9,10,1)
y = np.zeros(len(x))#y軸は直線表示のみ
plt.yticks([])#y軸のラベルを非表示
plt.title("原点からの計算で絶対値の距離を求める クイズ",fontname="MS Gothic")#タイトルを設定
plt.xticks(np.arange(-9,10,1))#小数点以下は切り捨て整数のみ表示
plt.grid(True)

plt.show()
```

```python
from numpy.random import *
import matplotlib
from matplotlib import pyplot as plt
import numpy as np
%matplotlib inline

# plot全体の高さを指定
fig = plt.figure(figsize=(10,1)) #figsize=(width,height)

# 0から4までの自然数を表示
x = np.arange(-2.9,0.1,0.1) #グラフの軸合わせで適当に加算
y = np.zeros(len(x))
plt.plot(x,y,color='green',linestyle='-',linewidth=6)
plt.text(0, 0, '原点0から数える',fontname="MS Gothic", fontsize=16)

x = np.arange(-9,9,1)
y = np.zeros(len(x))

x = np.arange(-9,10,1)
y = np.zeros(len(x))#y軸は直線表示のみ
plt.yticks([])#y軸のラベルを非表示
plt.title("原点からの計算で絶対値の距離を求める クイズ",fontname="MS Gothic")#タイトルを設定
plt.xticks(np.arange(-9,10,1))#小数点以下は切り捨て整数のみ表示
plt.grid(True)

plt.show()
```

> さてこの場合はどうなるでしょうか？絶対値０からマイナス方向に向かっています。<br>
答えは3です。絶対値から数えるだけでプラスもマイナスも関係ありません。
絶対値からの距離です。

家から南に進んで50メートル、北に進んでも50メートルは50メートルです。

原点は家だとすると考え方は簡単です。わかりにくいものは何かにたとえて考えます。

# 初歩的パイソンで数学を学ぶ 正の数と負の数

```python
# 分数を考える
A = 1/2 # Aは2分の1　分母が後ろにある

# 表示してみる
print(A)

```

    0.5

>Aという変数に2分1をを入れてみました。
>print(A)というのは()で囲んだAの内容を表示しています。
>これはAの値が2分1です。
>print(A)

そして答えが0.5になりました!

```python
from numpy.random import *
import matplotlib
from matplotlib import pyplot as plt
import numpy as np
%matplotlib inline

# plot全体の高さを指定
fig = plt.figure(figsize=(10,1)) #figsize=(width,height)

x = np.arange(-9,10,1)
y = np.zeros(len(x))#y軸は直線表示のみ
plt.yticks([])#y軸のラベルを非表示
plt.title("これらは整数",fontname="MS Gothic")#タイトルを設定
plt.xticks(np.arange(-9,10,1))#小数点以下は切り捨て整数のみ表示
plt.grid(True)

x = np.arange(-9,1,1)
y = np.zeros(len(x))
plt.plot(x,y,color='red',linestyle='-',linewidth=3)
plt.text(-8.5, 0, '負の数',fontname="MS Gothic", fontsize=16)

x = np.arange(0,10,1)
y = np.zeros(len(x))
plt.plot(x,y,color='green',linestyle='-',linewidth=3)
plt.text(8.5, 0, '正の数',fontname="MS Gothic", fontsize=16)

x = np.arange(0,0.1,1)
y = np.zeros(len(x))
plt.plot(x,y,color='blue',linestyle='-',linewidth=3)
plt.text(-0.5, 0, '原点',fontname="MS Gothic", fontsize=18)

plt.show()
```

0は整数です
そして0より0.5は大きい数です。つまり正の数になります。
0より大きければ正
0より小さければ負です。

簡単パイソンの言語で答えを表示することができます。

```
A = 1/2
print(A)
```
Aという変数で分数を計算できます。
A＝はAに入れるという意味です。（実際はメモリがうんたらという話になりますが今は覚える必要はありません）
数学とゲームを作る環境において変数を使うのは簡単です。

答えは2分の1が 0.5 になりました。
図と照らし合わせて0.5の位置を指さしてみましょう。
0と1の間にありますね？

緑色の部分は0より大きい数です。これは正の数です。
これはしつこいくらい言っています。なぜなら紛らわしいからです。

$
\begin{align}
    \frac{4}{8}
    \frac{5}{6}
    \frac{2}{4}
\end{align}
$

ここに3個の分数があります。これらも正の数です。分数に符号がついていなければ正の数です。

```python
# 分数を考える
A = 4/8 # Aは4分の8　分母が後ろにある
B = 5/6 # Bは5分の6　分母が後ろにある
C = 2/4 # Cは2分の4　分母が後ろにある

# 表示してみる
print(A)
print(B)
print(C)
```

    0.5
    0.8333333333333334
    0.5

答えが出ました。0より大きいので正の数です。
このようにパイソンで計算することができれば数学の構造がわかりやすくなります。

少し気になる人もいると思うのでこんなのやってみます。
#
$
\begin{align*}
A = \frac{-1}{3}
\end{align*}
$

```python
A = -1/3 # Aは-1分の3　分母が後ろにある
print(A)
```

    -0.3333333333333333

マイナスがつきました、つまり負の数です。

# 大なり小なりで比較をします

 <　> こんな形の記号です
 > 1は2より小さい、2は1より大きい
 1 < 2
 > 2は6より小さい、6は2より大きい
 6 > 2
パックマンの口が開いてる方が大きいということです。

\begin{align*}
    \frac{0.5}{3}

    \frac{5}{6}

    \frac{3}{5}

    0.7 を比較します
\end{align*}

＜＞記号で比較します。

そのためにまず　通分　という面倒なことをします。（本当に面倒）
だがしかしパイソンがあるから面倒なことはないでしょう（きっとです）

```python
# とにかく変数に入れてみましょう
A = 0.5/3 # 分母が後ろにあるのは覚えていますか？
B = 5/6
C = 3/5
D = 0.7

# 表示してみる
print("Aの答え", A)
print("Bの答え", B)
print("Cの答え", C)
print("Dの答え", D)

```

    Aの答え 0.16666666666666666
    Bの答え 0.8333333333333334
    Cの答え 0.6
    Dの答え 0.7

コードを書き換えて大なり小なりで比較してみましょう。

```python
# とにかく変数に入れてみましょう
A = 0.5/3 # 分母が後ろにあるのは覚えていますか？
B = 5/6
C = 3/5
D = 0.7

# 表示してみる
print("Aの答え", A)
print("Bの答え", B)
print("Cの答え", C)
print("Dの答え", D)

# AとBとCとDをリストにしてみましょう

数 = [A,B,C,D]

print("リストに入れた数を表示",数)
数.sort(reverse=True) # 数を絶対値(0)から離れてる順番でソートします
print("これできちんと並びました",数)

print("----------------------------------------------------")
# これではわかりずらいのでABCDの形を維持したまま
# A:中身の答えのように辞書形式の配列にしてみましょう。

A = 0.5/3
B = 5/6
C = 3/5
D = 0.7

辞書配列A = {'エリエール':A}
辞書配列B = {'スコッティ':B}
辞書配列C = {'マントヒヒ':C}
辞書配列D = {'ポテトサラダ':D}

# 辞書配列から数値のみを取り出してみましょう
print("辞書配列Aの中身",辞書配列A['エリエール'])
print("辞書配列Bの中身",辞書配列B['スコッティ'])
print("辞書配列Cの中身",辞書配列C['マントヒヒ'])
print("辞書配列Dの中身",辞書配列D['ポテトサラダ'])

```

    Aの答え 0.16666666666666666
    Bの答え 0.8333333333333334
    Cの答え 0.6
    Dの答え 0.7
    リストに入れた数を表示 [0.16666666666666666, 0.8333333333333334, 0.6, 0.7]
    これできちんと並びました [0.8333333333333334, 0.7, 0.6, 0.16666666666666666]
    ----------------------------------------------------
    辞書配列Aの中身 0.16666666666666666
    辞書配列Bの中身 0.8333333333333334
    辞書配列Cの中身 0.6
    辞書配列Dの中身 0.7

辞書配列というのは　キーワード：中身　のような考え方がわかりやすい覚え方です。

エリエールの中にＡをいれてみました。
A = 0.5/3　エリエール
B = 5/6　スコッティ
C = 3/5　マントヒヒ
D = 0.7　ポテトサラダ

紛らわしいです
名前とペアで付けられるので、いろいろな用途に使えます。
意味不明な変数名をつけるとわかりずらくなるのでやめましょう

```python
# 辞書配列をリスト配列にしてみましょう
辞書配列A = {'エリエール':A}
辞書配列B = {'スコッティ':B}
辞書配列C = {'マントヒヒ':C}
辞書配列D = {'ポテトサラダ':D}

# 辞書配列の中身を表示
print("辞書配列Aの中身",辞書配列A)
print("辞書配列Bの中身",辞書配列B)
print("辞書配列Cの中身",辞書配列C)
print("辞書配列Dの中身",辞書配列D)

# 辞書配列から取り出した数値のみを取り出す
辞書配列数値 = [辞書配列A['エリエール'],辞書配列B['スコッティ'],辞書配列C['マントヒヒ'],辞書配列D['ポテトサラダ']]
辞書配列数値 = list(辞書配列数値) # リストに変換

# 表示してみる
print("リストにした数値のみを表示してみる")
print("辞書配列数値",辞書配列数値)

# sortで降順に並び替え
辞書配列数値.sort(reverse=True)

#　表示してみる
print("リストにした数値のみを表示してみる（ソート済み）")
print("辞書配列数値",辞書配列数値)

```

    辞書配列Aの中身 {'エリエール': 0.16666666666666666}
    辞書配列Bの中身 {'スコッティ': 0.8333333333333334}
    辞書配列Cの中身 {'マントヒヒ': 0.6}
    辞書配列Dの中身 {'ポテトサラダ': 0.7}
    リストにした数値のみを表示してみる
    辞書配列数値 [0.16666666666666666, 0.8333333333333334, 0.6, 0.7]
    リストにした数値のみを表示してみる（ソート済み）
    辞書配列数値 [0.8333333333333334, 0.7, 0.6, 0.16666666666666666]

ここで使った関数は　sort そして list さらに辞書であるDictionaryも使用しました。
紛らわしい変数名がいかに混乱を生むかが体験できました。

```python
A = 0.5/3
B = 5/6
C = 3/5
D = 0.7

# AやBは小数点があるので、一桁で表示してみましょう
A = round(A,1)
B = round(B,1)
print("Aの答え",A)
print("Bの答え",B)

辞書 = [{'式':'0.5/3', '解':A},{'式':'5/6', '解':B},{'式':'3/5', '解':C},{'式':'0.7', '解':D}]
並び変えた辞書 = sorted(辞書, key=lambda x:x['解'])
print(並び変えた辞書)
```

    Aの答え 0.2
    Bの答え 0.8
    [{'式': '0.5/3', '解': 0.2}, {'式': '3/5', '解': 0.6}, {'式': '0.7', '解': 0.7}, {'式': '5/6', '解': 0.8}]

> これでほぼ元の形でみることができます。

\begin{align*}
    \frac{0.5}{3}

    \frac{5}{6}

    \frac{3}{5}

    0.7 を比較します

\end{align*}

結果が示す通りの順番で０の原点から順に並んでいます。
0.2 < 0.6 < 0.7 < 0.8

\begin{align*}
    \frac{0.5}{3} < \frac{5}{6} < \frac{3}{5} < 0.7
\end{align*}

大なり小なりです、パックマンの口が開いている方が大きいということです。


```python
"""
IPython Notebook v4.0 para python 2.7
Librerías adicionales: numpy, matplotlib
Contenido bajo licencia CC-BY 4.0. Código bajo licencia MIT. (c) Sebastian Flores.
"""

# Configuracion para recargar módulos y librerías
%reload_ext autoreload
%autoreload 2

from IPython.core.display import HTML

HTML(open("style/mat281.css", "r").read())
```

# MAT281
## Aplicaciones de la Matemática en la Ingeniería

### Sebastián Flores

https://www.github.com/sebastiandres/mat281

## Clase anterior

* Teorema $\Pi$.

## ¿Qué contenido aprenderemos hoy?

* Adimensionalización de ecuaciones.
* Diseño de experimentos.

## ¿Porqué aprenderemos ese contenido?

* **Adimensionalización de ecuaciones.**

Permite estudiar las ecuaciones con el mínimo número de parámetros.

* **Diseño de experimentos.**

Permite simular un experimento con el menor número de ejecuciones.

## Contradicción.
¿Han notado la contradicción de las últimas clases?

* Clase $i$: Las dimensiones son lo más importante de un problema.

* Clase $i+1$: Es mejor hacer un análisis en adimensional.

## Motivación
Si el teorema $\Pi$ es tan bueno, ¿para qué necesitamos ecuaciones?

* **Teorema de $\Pi$ o Teorema Buckingham**: Conocimiento indicativo de cómo se podrían relacionar las variables.
* **Adimensionalización de ecuaciones**: Conocimiento funcional de cómo se relacionan las variables y la importancia relativa de cada término.

En términos de información:

Ecuaciones dimensionales $>>$ Ecuaciones Adimensionales $>>$ Teorema $\Pi$

#### Análisis dimensional
## Ejemplo
Consideremos el ejemplo clásico de una barra de longitud infinita, de sección transversal $A$ y que se encuentra inicialmente a una temperatura $\tau_a$.

En $t = 0$ la barra se calienta en $x = 0$ a una temperatura $\tau_b$.

¿Cómo evoluciona la temperatura en las distintas posiciones de la barra, para los tiempos posteriores?

En particular, ¿cuál es la temperatura de la barra en el tiempo $t$ en la posición $x$?

¿Qué nos dice el Teorema $\Pi$? ¿Qué nos dice el análisis dimensional de las ecuaciones?

#### Ejemplo
## Teorema Pi
¿Que variables hay? Hint: son 9.

* $t$: tiempo. Dimensión. [$T$].
* $x$: posición. Dimensión [$L$].
* Temperaturas. Dimensión [$\tau$]
  * $\tau_a$: Temperatura inicial de la barra.
  * $\tau_b$: Temperatura en extremo.
  * $\tau$: Temperatura en $x$ y $t$.
* $A$: sección transversal. Dimensión $[L^2]$.
* $\rho$: densidad. Dimensión $\Big[\frac{M}{L^3}\Big]$.
* $c_p$: calor específico. Dimensión $\Big[\frac{L^2}{T^2 \theta}\Big]$.
* $k$: conductividad térmica. Dimensión $\Big[\frac{M L }{T^3 \theta}\Big]$.

# Densidad: $\rho$
* Relaciona masa con volumen.
* Unidades: $$\frac{kg}{m^3}$$
* Dimensión: $$\Big[\frac{M}{L^3}\Big]$$
* Ejemplos:
  * Cobre: 8960 $\frac{kg}{m^3}$
  * Hierro: 7870 $\frac{kg}{m^3}$
  * Oro: 19320 $\frac{kg}{m^3}$

# Calor Específico: $c_p$
* Relaciona energía proporcionada con aumento de temperatura.
* El calor específico es cantidad de calor (energía) a suministrar a 1 kg de material para aumentar la temperatura en 1 grado Kelvin.
* Unidades: $$\frac{J}{kg K}$$
* Dimensión: $$\Big[\frac{L^2}{T^2 \theta}\Big]$$
* Ejemplos:
  * Cobre: 385 $\frac{J}{kg K}$
  * Hierro: 450 $\frac{J}{kg K}$
  * Oro: 129 $\frac{J}{kg K}$

## Conductividad térmica: $k$
* Se relaciona con el flujo de calor dentro un material.
* La conductividad térmica es una propiedad del material, e indica cuanto calor (energía) se transmitiría en un segundo entre 2 caras de un metro cuadrado separadas a un metro de distancia.
* Unidades: $$\frac{W}{m K}$$
* Dimensión: $$\Big[\frac{M L}{T^3 \theta}\Big]$$
* Ejemplos:
  * Cobre: 380 $\frac{W}{m K}$
  * Hierro: 80 $\frac{W}{m K}$
  * Oro: 308 $\frac{W}{m K}$

#### Ejemplo
## Teorema Pi
Hay $9$ variables y $4$ dimensiones, por lo que el problema requiere definir $9-4=5$ parámetros adimensionales.

Si elegimos como base: $\tau_a$, $x$, $t$, $c_p$.

$$\Pi_{\tau} = \Phi(\Pi_{\tau_b} , \Pi_{A} , \Pi_{\rho} , \Pi_{k} )$$
No es particularmente prometedor. Sabemos que existe una relación, pero no sabemos cómo obtenerla.

¿Es lo mejor que podemos hacer?

¿Cómo mejora la situación si sabemos cómo se relacionan físicamente las variables?

#### Ejemplo
## Modelamiento físico

Sabemos que para este problema aplican las siguientes ecuaciones, donde $q$ es el flujo de calor:

* Conservación de calor:
$$
\rho c_p \frac{\partial \tau}{\partial t} = - \frac{\partial q}{\partial x}
$$
* Ley de Fourier:
$$
q = -k \frac{\partial \tau}{\partial x}$$
OBS: No hay referencia a la sección transversal.

#### Ejemplo
## Modelamiento físico
Si suponemos $k$ constante obtenemos:
$$
\frac{\partial \tau}{\partial t} = \frac{k}{\rho c_p} \frac{\partial^2 \tau}{\partial x^2}$$

La constante $D =\frac{k}{\rho c_p}$ se llama **constante de difusividad** y tiene dimensión $\Big[ \frac{L^2}{T} \Big]$.

Normalmente los problemas hablan directamente de $D$ y olvidan las aproximaciones realizadas.

Ejemplos:
  * Cobre: $1.10 \cdot 10^{-4}$ $\frac{m^2}{s}$
  * Hierro: $2.25 \cdot 10^{-5}$ $\frac{m^2}{s}$
  * Oro: $1.23 \cdot 10^{-4}$ $\frac{m^2}{s}$

#### Ejemplo
## Sistema dimensional
Hemos obtenido
$$
\begin{align}
\frac{\partial \tau}{\partial t} &= \Big( \frac{k}{\rho c_p} \Big) \frac{\partial^2 \tau}{\partial x^2}\\
\tau(x=0, t=0)&= \tau_b \\
\tau(x\neq 0, t=0)&= \tau_a \\
\end{align}
$$
Con ello  tenemos que $\tau= \Phi(x, t, \frac{k}{\rho c_p}, \tau_a, \tau_b)$.
* Hemos obtenido que la temperatura depende de 2 variables y 3 parámetros.
* Esto es similar en complejidad a lo que se obtenida con el teorema $\Pi$.
* Simplificación no ha utilizado las dimensiones, sino la física del problema.

#### Ejemplo
## Adimensionalización
Adimensionalicemos las ***variables*** de la ecuación anterior.

Partamos por las variables dependientes:
$$
\begin{align}
\tau &= \tau_0 \ \hat{\tau} \\
x &= x_0 \ \hat{x} \\
t &= t_0 \ \hat{t}
\end{align}
$$
Donde todavía no decidimos que utilizaremos como factores de escalamiento $\tau_0$, $x_0$ y $t_0$.

#### Ejemplo
## Adimensionalización de derivadas
Para la derivada temporal
$$
\begin{align}
\frac{\partial \tau}{\partial t} & = \frac{\partial \tau_0 \hat{\tau}}{\partial t} = \tau_0 \frac{\partial \hat{\tau}}{\partial t} \\
& = \tau_0 \frac{\partial \hat{\tau}}{t_0 \partial \hat{t}}
= \frac{\tau_0}{t_0} \frac{\partial \hat{\tau}}{\partial \hat{t}}
\end{align}
$$
y similarmente para la segunda derivada espacial
$$
\begin{align}
\frac{\partial^2 \tau}{\partial x^2} &=
\frac{\partial}{\partial x} \frac{\partial \tau}{\partial x} =
\frac{1}{x_0} \frac{\partial}{\partial \hat{x}} \frac{\tau_0}{x_0} \frac{\partial \hat{\tau}}{\partial \hat{x}} \\
&= \frac{\tau_0}{x_0^2} \frac{\partial}{\partial \hat{x}} \frac{\partial \hat{\tau}}{\partial \hat{x}} =  \frac{\tau_0}{x_0^2} \frac{\partial^2 \hat{\tau}}{\partial \hat{x}^2}
\end{align}
$$

#### Ejemplo
## Adimensionalización de ecuación
Utilizando lo anterior
$$
\frac{\partial \tau}{\partial t} = \frac{k}{\rho c_p} \frac{\partial^2 \tau}{\partial x^2}
$$
se convierte en
$$
\frac{\tau_0}{t_0} \frac{\partial \hat{\tau}}{\partial \hat{t}} = \frac{k}{\rho c_p} \frac{\tau_0}{x_0^2} \frac{\partial^2 \hat{\tau}}{\partial \hat{x}^2}
$$
es decir
$$
\frac{\partial \hat{\tau}}{\partial \hat{t}} = \Big( \frac{k}{\rho c_p} \frac{t_0}{x_0^2} \Big) \frac{\partial^2 \hat{\tau}}{\partial \hat{x}^2}
$$

#### Ejemplo
## Adimensionalización de Condiciones Iniciales
$$
\begin{align}
\tau(x=0, t=0)&= \tau_b \\
\tau(x\neq 0, t=0)&= \tau_a \\
\end{align}
$$
se convierte en
$$
\begin{align}
\hat{\tau}(\hat{x}=0, \hat{t}=0)&= \frac{\tau_b}{\tau_0} \\
\hat{\tau}(\hat{x}\neq 0, \hat{t}=0)&= \frac{\tau_a}{\tau_0} \\
\end{align}
$$

#### Ejemplo
## Sistema adimensional final
Hemos obtenido
$$
\begin{align}
\frac{\partial \hat{\tau}}{\partial \hat{t}} &= \Big( \frac{k}{\rho c_p} \frac{t_0}{x_0^2} \Big) \frac{\partial^2 \hat{\tau}}{\partial \hat{x}^2}\\
\hat{\tau}(\hat{x}=0, \hat{t}=0)&= \frac{\tau_b}{\tau_0} \\
\hat{\tau}(\hat{x}\neq 0, \hat{t}=0)&= \frac{\tau_a}{\tau_0} \\
\end{align}
$$
Es posible y conveniente elegir la adimensionalización de modo que
$$\begin{align}
\frac{k}{\rho c_p} \frac{t_0}{x_0^2} &= 1 \\
\frac{\tau_a}{\tau_0} &=1
\end{align}$$

#### Ejemplo
## Elección de adimensionalización
Si sabemos que se simulará hasta un tiempo máximo $t_{max}$, es conveniente tomar:
$$
\begin{align}
t_0 &= t_{max} \\
x_0 &= \sqrt{\frac{k}{\rho c_p} t_{max}}\\
\tau_0 &= \tau_a
\end{align}
$$

#### Ejemplo
## Elección de adimensionalización
Si sabemos que se estudiará un punto $x_L$ en específico, es conveniente tomar:
$$
\begin{align}
t_0 &= \frac{\rho c_p}{k} x_0^2\\
x_0 &= x_L\\
\tau_0 &= \tau_a
\end{align}
$$

#### Ejemplo
## Sistema adimensional final
Independiente de la adimensionalización, se obtiene finalmente el sistema:
$$
\begin{align}
\frac{\partial \hat{\tau}}{\partial \hat{t}} &= \frac{\partial^2 \hat{\tau}}{\partial \hat{x}^2}\\
\hat{\tau}(\hat{x}=0, \hat{t}=0)&= \frac{\tau_b}{\tau_a} \\
\hat{\tau}(\hat{x}\neq 0, \hat{t}=0)&= 1
\end{align}
$$

#### Ejemplo
## Balance
La temperatura adimensional depende de 2 variables $\hat{x}$ y $\hat{t}$ y un parámetro adimensional $\frac{\tau_b}{\tau_a}$, esto es,

$$\hat{\tau}= \Phi\Big(\hat{x}, \hat{t}, \frac{\tau_b}{\tau_a}\Big)$$

Un problema que inicialmente dependía de 6 parámetros físicos ($A$, $c_p$, $k$, $\rho$, $\tau_a$, $\tau_b$), puede ser resuelto solamente por 1 parámetro ($\tau_b/\tau_a$) y luego escalado correctamente.

## Balance
No sólo hemos resuelto para un menor número de parámetros, sino que la ecuación anterior indica que basta resolver para una combinación $\tau_b/\tau_a$ específica y que luego podemos recuperar la temperatura dimensional para cualquier valor $c_p$ y $k$ simplemente escalando correctamente.

Esto es, si resolvemos y conocemos
$$\hat{\tau}= \Phi\Big(\hat{x}, \hat{t}, \tau_b/\tau_a\Big)$$
podemos ahora calcular la versión dimensional utilizando
$$\tau = t_0 \hat{\tau}= t_0 \Phi\Big(x/x_0, t/t_0, \tau_b/\tau_a\Big)$$
Los coeficientes $\rho$, $c_p$ y $k$ se encuentran "camuflados" en las definiciones de $x_0$ y $t_0$.

## Moralejas
* Una ecuación contiene mucha más información que el teorema de Buckingham.
* Adimensionalizar ecuaciones permite chequear factibilidad, reducir a términos elementales y estudiar casos límites.
* Teorema de Buckingham es útil para realizar estimaciones de  comportamiento global, pero no para comportamiento local.

## Aplicación
Supongamos que para un experimento queremos saber cuánto tiempo se demora en llegar al 50% de la temperatura deseada, estando a 0.50 metro del origen, en funcion de los parámetros.
* ¿Cómo varía el resultado en función de las temperaturas $\tau_a$ (inicial) y $\tau_b$ (fija)?
* ¿Cómo varía el resultado en función de los coeficientes $\rho$, $c_p$ y $k$?

#### Aplicación
## Simulación con parametros dimensionales
Para resolver el problema con parametros dimensionales ($\tau_a$, $\tau_b$, $\rho$, $c_p$, $k$)  deberíamos realizar simulaciones en un gran espacio.

Si discretizamos el espacio de cada parámetro en 10 valores, se requerirían $10^5$ simulaciones.
Si cada simulacion toma $1$ segundo, se requerirán $10^5$ segundos, es decir, $27$ horas.

Si discretizamos el espacio de cada parámetro en 20 valores, se requerirían $20^5$ simulaciones.
Si cada simulacion toma $1$ segundo, se requerirán $20^5$ segundos, es decir, $36$ días.

#### Aplicación
## Simulación con parametros adimensionales

Para resolver el problema con parametros dimensionales deberíamos realizar simulaciones simplemente discretizando el parámetro $\tau_b/\tau_a$.

#### Aplicación
## Simulación con parametros adimensionales
Tomemos el caso del cobre:
* Pensemos que $\tau_a$ y $\tau_b$ se mueven en el rango 273-373 grados Kelvin.
* Eso significa que $\frac{273}{373} \leq \frac{\tau_b}{\tau_a} \leq \frac{373}{273}$.
* Recordemos que deseamos llegar al 50% de la temperatura $\tau_b$, estando a 0.50 metro del origen.

## Solución
En python y magia HTML

```python
from IPython.display import HTML
from mat281_code import heat
HTML(heat.run())
```

$\tau_b / \tau_a$ [1]	$\hat{t}^*$ [1]

0.731903485255	0.38064993368

0.802392027593	0.38064993368

0.872880569932	0.38064993368

0.94336911227	0.38064993368

1.01385765461	0.38064993368

1.08434619695	0.38064993368

1.15483473929	0.38064993368

1.22532328162	0.38064993368

1.29581182396	0.38064993368

1.3663003663	0.38064993368

## Interpretación

El tiempo (adimensional) que le toma llegar a la mitad de la temperatura es independiente de las temperaturas elegidas.

Volviendo a parametros dimensionales, tenemos:
$$ t^* = t_0 \hat{t}^* = \frac{x_0^2}{D} \ \  \hat{t}^* = \frac{\rho c_p}{k} x_0^2 \ \  \hat{t}^*$$

* Si el material fuera oro, el tiempo requerido hubiese sido $t^* = \frac{0.5^2}{1.23E-4} \times 0.381 \approx 774.4$ segundos (13 minutos).
* Si el material fuera cobre, el tiempo requerido hubiese sido $t^* = \frac{0.5^2}{1.10E-4} \times 0.381 \approx 865.5$ segundos (15 minutos).
* Si el material fuera fierro, el tiempo requerido hubiese sido $t^* = \frac{0.5^2}{2.25E-5} \times 0.381 \approx 4329.5$ segundos (72 minutos).

## Discusión del problema
¿Que tan real es el problema?
* ¿Barra infinita?
* ¿Fijar temperatura en $x=0$ a una temperatura fija?