Escuela de Ciencias Básicas, Tecnología e Ingeniería

ECBTI

Curso: Métodos Numéricos

Unidad 1: Error

Febrero 28 de 2020

***

> **Tutor:** Carlos Alberto Álvarez Henao, I.C. D.Sc.

> **skype:** carlos.alberto.alvarez.henao

> **Herramienta:** [Jupyter](http://jupyter.org/)

> **Kernel:** Python 3.7

***

***Comentario:*** estas notas están basadas en el curso del profesor [Kyle T. Mandli](https://github.com/mandli/intro-numerical-methods) (en inglés)

# Fuentes de error

Los cálculos numéricos, que involucran el uso de máquinas (análogas o digitales) presentan una serie de errores que provienen de diferentes fuentes:

- del Modelo
- de los datos
- de truncamiento
- de representación de los números (punto flotante)
- $\ldots$

***Meta:*** Categorizar y entender cada tipo de error y explorar algunas aproximaciones simples para analizarlas.

# Error en el modelo y los datos

Errores en la formulación fundamental

- Error en los datos: imprecisiones en las mediciones o incertezas en los parámetros

Infortunadamente no tenemos control de los errores en los datos y el modelo de forma directa pero podemos usar métodos que pueden ser más robustos en la presencia de estos tipos de errores.

# Error de truncamiento

Los errores surgen de la expansión de funciones con una función simple, por ejemplo, $sin(x) \approx x$ para $|x|\approx0$.

# Error de  representación de punto fotante

Los errores surgen de aproximar números reales con la representación  en precisión finita de números en el computador.

# Definiciones básicas

Dado un valor verdadero de una función $f$ y una solución aproximada $F$, se define:

- Error absoluto

$$e_a=|f-F|$$

- Error relativo

$$e_r = \frac{e_a}{|f|}=\frac{|f-F|}{|f|}$$

# Notación $\text{Big}-\mathcal{O}$

sea $$f(x)= \mathcal{O}(g(x)) \text{ cuando } x \rightarrow a$$

si y solo si

$$|f(x)|\leq M|g(x)| \text{ cuando } |x-a| < \delta \text{ donde } M, a > 0$$

En la práctica, usamos la notación $\text{Big}-\mathcal{O}$ para decir algo sobre cómo se pueden comportar los términos que podemos haber dejado fuera de una serie. Veamos el siguiente ejemplo de la aproximación de la serie de Taylor:

***Ejemplo:***

sea $f(x) = \sin x$ con $x_0 = 0$ entonces

$$T_N(x) = \sum^N_{n=0} (-1)^{n} \frac{x^{2n+1}}{(2n+1)!}$$

Podemos escribir $f(x)$ como

$$f(x) = x - \frac{x^3}{6} + \frac{x^5}{120} + \mathcal{O}(x^7)$$

Esto se vuelve más útil cuando lo vemos como lo hicimos antes con $\Delta x$:

$$f(x) = \Delta x - \frac{\Delta x^3}{6} + \frac{\Delta x^5}{120} + \mathcal{O}(\Delta x^7)$$

# Reglas para el error de propagación basado en la notación $\text{Big}-\mathcal{O}$

En general, existen dos teoremas que no necesitan prueba y se mantienen cuando el valor de $x$ es grande:

Sea

$$\begin{aligned}
    f(x) &= p(x) + \mathcal{O}(x^n) \\
    g(x) &= q(x) + \mathcal{O}(x^m) \\
    k &= \max(n, m)
\end{aligned}$$

Entonces

$$
    f+g = p + q + \mathcal{O}(x^k)
$$

y

\begin{align}
    f \cdot g &= p \cdot q + p \mathcal{O}(x^m) + q \mathcal{O}(x^n) + O(x^{n + m}) \\
    &= p \cdot q + \mathcal{O}(x^{n+m})
\end{align}

De otra forma, si estamos interesados en valores pequeños de $x$, $\Delta x$, la expresión puede ser modificada como sigue:

\begin{align}
    f(\Delta x) &= p(\Delta x) + \mathcal{O}(\Delta x^n) \\
    g(\Delta x) &= q(\Delta x) + \mathcal{O}(\Delta x^m) \\
    r &= \min(n, m)
\end{align}

entonces

$$
    f+g = p + q + O(\Delta x^r)
$$

y

\begin{align}
    f \cdot g &= p \cdot q + p \cdot \mathcal{O}(\Delta x^m) + q \cdot \mathcal{O}(\Delta x^n) + \mathcal{O}(\Delta x^{n+m}) \\
    &= p \cdot q + \mathcal{O}(\Delta x^r)
\end{align}

***Nota:*** En este caso, supongamos que al menos el polinomio con $k=max(n,m)$ tiene la siguiente forma:

$$
    p(\Delta x) = 1 + p_1 \Delta x + p_2 \Delta x^2 + \ldots
$$

o

$$
    q(\Delta x) = 1 + q_1 \Delta x + q_2 \Delta x^2 + \ldots
$$

para que $\mathcal{O}(1)$

de modo que hay un término $\mathcal{O}(1)$ que garantiza la existencia de $\mathcal{O}(\Delta x^r)$ en el producto final.

Para tener una idea de por qué importa más la potencia en $\Delta x$ al considerar la convergencia, la siguiente figura muestra cómo las diferentes potencias en la tasa de convergencia pueden afectar la rapidez con la que converge nuestra solución. Tenga en cuenta que aquí estamos dibujando los mismos datos de dos maneras diferentes. Graficar el error como una función de $\Delta x$ es una forma común de mostrar que un método numérico está haciendo lo que esperamos y muestra el comportamiento de convergencia correcto. Dado que los errores pueden reducirse rápidamente, es muy común trazar este tipo de gráficos en una escala log-log para visualizar fácilmente los resultados. Tenga en cuenta que si un método fuera realmente del orden $n$, será una función lineal en el espacio log-log con pendiente $n$.

```python
import numpy as np
import matplotlib.pyplot as plt
```

```python
dx = np.linspace(1.0, 1e-4, 100)

fig = plt.figure()
fig.set_figwidth(fig.get_figwidth() * 2.0)
axes = []
axes.append(fig.add_subplot(1, 2, 1))
axes.append(fig.add_subplot(1, 2, 2))

for n in range(1, 5):
    axes[0].plot(dx, dx**n, label="$\Delta x^%s$" % n)
    axes[1].loglog(dx, dx**n, label="$\Delta x^%s$" % n)

axes[0].legend(loc=2)
axes[1].set_xticks([10.0**(-n) for n in range(5)])
axes[1].set_yticks([10.0**(-n) for n in range(16)])
axes[1].legend(loc=4)
for n in range(2):
    axes[n].set_title("Crecimiento del Error vs. $\Delta x^n$")
    axes[n].set_xlabel("$\Delta x$")
    axes[n].set_ylabel("Error Estimado")
    axes[n].set_title("Crecimiento de las diferencias")
    axes[n].set_xlabel("$\Delta x$")
    axes[n].set_ylabel("Error Estimado")

plt.show()
```

# Error de truncamiento

***Teorema de Taylor:*** Sea $f(x) \in C^{m+1}[a,b]$ y $x_0 \in [a,b]$, para todo $x \in (a,b)$ existe un número $c = c(x)$ que se encuentra entre $x_0$ y $x$ tal que

$$ f(x) = T_N(x) + R_N(x)$$

donde $T_N(x)$ es la aproximación del polinomio de Taylor

$$T_N(x) = \sum^N_{n=0} \frac{f^{(n)}(x_0)\times(x-x_0)^n}{n!}$$

y $R_N(x)$ es el residuo (la parte de la serie que obviamos)

$$R_N(x) = \frac{f^{(n+1)}(c) \times (x - x_0)^{n+1}}{(n+1)!}$$

Otra forma de pensar acerca de estos resultados consiste en reemplazar $x - x_0$ con $\Delta x$. La idea principal es que el residuo $R_N(x)$ se vuelve mas pequeño cuando $\Delta x \rightarrow 0$.

$$T_N(x) = \sum^N_{n=0} \frac{f^{(n)}(x_0)\times \Delta x^n}{n!}$$

y $R_N(x)$ es el residuo (la parte de la serie que obviamos)

$$ R_N(x) = \frac{f^{(n+1)}(c) \times \Delta x^{n+1}}{(n+1)!} \leq M \Delta x^{n+1}$$

***Ejemplo 1:***

$f(x) = e^x$ con $x_0 = 0$

Usando esto podemos encontrar expresiones para el error relativo y absoluto en función de $x$ asumiendo $N=2$.

Derivadas:
$$\begin{aligned}
    f'(x) &= e^x \\
    f''(x) &= e^x \\
    f^{(n)}(x) &= e^x
\end{aligned}$$

Polinomio de Taylor:
$$\begin{aligned}
    T_N(x) &= \sum^N_{n=0} e^0 \frac{x^n}{n!} \Rightarrow \\
    T_2(x) &= 1 + x + \frac{x^2}{2}
\end{aligned}$$

Restos:
$$\begin{aligned}
    R_N(x) &= e^c \frac{x^{n+1}}{(n+1)!} = e^c \times \frac{x^3}{6} \quad \Rightarrow \\
    R_2(x) &\leq \frac{e^1}{6} \approx 0.5
\end{aligned}$$

Precisión:
$$
    e^1 = 2.718\ldots \\
    T_2(1) = 2.5 \Rightarrow e \approx 0.2 ~~ r \approx 0.1
$$

¡También podemos usar el paquete `sympy` que tiene la capacidad de calcular el polinomio de *Taylor* integrado!

```python
import sympy
x = sympy.symbols('x')
f = sympy.symbols('f', cls=sympy.Function)

f = sympy.exp(x)
f.series(x0=0, n=5)
```

$\displaystyle 1 + x + \frac{x^{2}}{2} + \frac{x^{3}}{6} + \frac{x^{4}}{24} + O\left(x^{5}\right)$

Graficando

```python
x = np.linspace(-1, 1, 100)
T_N = 1.0 + x + x**2 / 2.0
R_N = np.exp(1) * x**3 / 6.0

plt.plot(x, T_N, 'r', x, np.exp(x), 'k', x, R_N, 'b')
plt.plot(0.0, 1.0, 'o', markersize=10)
plt.grid(True)
plt.xlabel("x")
plt.ylabel("$f(x)$, $T_N(x)$, $R_N(x)$")
plt.legend(["$T_N(x)$", "$f(x)$", "$R_N(x)$"], loc=2)
plt.show()
```

***Ejemplo 2:***

Aproximar

$$ f(x) = \frac{1}{x} \quad x_0  = 1,$$

usando $x_0 = 1$ para el tercer termino de la serie de Taylor.

$$\begin{aligned}
    f'(x) &= -\frac{1}{x^2} \\
    f''(x) &= \frac{2}{x^3} \\
    f^{(n)}(x) &= \frac{(-1)^n n!}{x^{n+1}}
\end{aligned}$$

$$\begin{aligned}
    T_N(x) &= \sum^N_{n=0} (-1)^n (x-1)^n \Rightarrow \\
    T_2(x) &= 1 - (x - 1) + (x - 1)^2
\end{aligned}$$

$$\begin{aligned}
    R_N(x) &= \frac{(-1)^{n+1}(x - 1)^{n+1}}{c^{n+2}} \Rightarrow \\
    R_2(x) &= \frac{-(x - 1)^{3}}{c^{4}}
\end{aligned}$$

```python
x = np.linspace(0.8, 2, 100)
T_N = 1.0 - (x-1) + (x-1)**2
R_N = -(x-1.0)**3 / (1.1**4)

plt.plot(x, T_N, 'r', x, 1.0 / x, 'k', x, R_N, 'b')
plt.plot(1.0, 1.0, 'o', markersize=10)
plt.grid(True)
plt.xlabel("x")
plt.ylabel("$f(x)$, $T_N(x)$, $R_N(x)$")

plt.legend(["$T_N(x)$", "$f(x)$", "$R_N(x)$"], loc=8)
plt.show()
```

# En esta celda haz tus comentarios

Esta cosa con esta vaina quizas tal vez-.-.--

## Error de punto flotante

Errores surgen de aproximar números reales con números de precisión finita

$$\pi \approx 3.14$$

o $\frac{1}{3} \approx 0.333333333$ en decimal, los resultados forman un número finito de registros para representar cada número.

### Sistemas de punto flotante

Los números en sistemas de punto flotante se representan como una serie de bits que representan diferentes partes de un número. En los sistemas de punto flotante normalizados, existen algunas convenciones estándar para el uso de estos bits. En general, los números se almacenan dividiéndolos en la forma

$$F = \pm d_1 . d_2 d_3 d_4 \ldots d_p \times \beta^E$$

donde

1. $\pm$ es un bit único y representa el signo del número.

2. $d_1 . d_2 d_3 d_4 \ldots d_p$ es la *mantisa*. observe que, técnicamente, el decimal se puede mover, pero en general, utilizando la notación científica, el decimal siempre se puede colocar en esta ubicación. Los digitos $d_2 d_3 d_4 \ldots d_p$ son llamados la *fracción* con $p$ digitos de precisión. Los sistemas normalizados específicamente ponen el punto decimal en el frente y asume $d_1 \neq 0$ a menos que el número sea exactamente $0$.

3. $\beta$ es la *base*. Para el sistema binario $\beta = 2$, para decimal $\beta = 10$, etc.

4. $E$ es el *exponente*, un entero en el rango $[E_{\min}, E_{\max}]$

Los puntos importantes en cualquier sistema de punto flotante es

1. Existe un conjunto discreto y finito de números representables.

2. Estos números representables no están distribuidos uniformemente en la línea real

3. La aritmética en sistemas de punto flotante produce resultados diferentes de la aritmética de precisión infinita (es decir, matemática "real")

### Propiedades de los sistemas de punto flotante

Todos los sistemas de punto flotante se caracterizan por varios números importantes

- Número normalizado reducido (underflow si está por debajo, relacionado con números sub-normales alrededor de cero)

- Número normalizado más grande (overflow)

- Cero

- $\epsilon$ o $\epsilon_{mach}$

- `Inf` y `nan`

***Ejemplo: Sistema de juguete***

Considere el sistema decimal de 2 digitos de  precisión (normalizado)

$$f = \pm d_1 . d_2 \times 10^E$$

con $E \in [-2, 0]$.

**Numero y distribución de números**

1. Cuántos números pueden representarse con este sistema?

2. Cuál es la distribución en la línea real?

3. Cuáles son los límites underflow y overflow?

Cuántos números pueden representarse con este sistema?

$$f = \pm d_1 . d_2 \times 10^E ~~~ \text{with} E \in [-2, 0]$$

$$2 \times 9 \times 10 \times 3 + 1 = 541$$

Cuál es la distribución en la línea real?

```python
d_1_values = [1, 2, 3, 4, 5, 6, 7, 8, 9]
d_2_values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
E_values = [0, -1, -2]

fig = plt.figure(figsize=(10.0, 1.0))
axes = fig.add_subplot(1, 1, 1)

for E in E_values:
    for d1 in d_1_values:
        for d2 in d_2_values:
            axes.plot( (d1 + d2 * 0.1) * 10**E, 0.0, 'r+', markersize=20)
            axes.plot(-(d1 + d2 * 0.1) * 10**E, 0.0, 'r+', markersize=20)

axes.plot(0.0, 0.0, '+', markersize=20)
axes.plot([-10.0, 10.0], [0.0, 0.0], 'k')

axes.set_title("Distribución de Valores")
axes.set_yticks([])
axes.set_xlabel("x")
axes.set_ylabel("")
axes.set_xlim([-0.1, 0.1])
plt.show()
```

Cuáles son los límites superior (overflow) e inferior (underflow)?

- El menor número que puede ser representado (underflow) es: $1.0 \times 10^{-2} = 0.01$

- El mayor número que puede ser representado (overflow) es:  $9.9 \times 10^0 = 9.9$

### Sistema Binario

Considere el sistema en base 2 de 2 dígitos de precisión

$$f=\pm d_1 . d_2 \times 2^E \quad \text{with} \quad E \in [-1, 1]$$

#### Numero y distribución de números**

1. Cuántos números pueden representarse con este sistema?

2. Cuál es la distribución en la línea real?

3. Cuáles son los límites underflow y overflow?

Cuántos números pueden representarse en este sistema?

$$f=\pm d_1 . d_2 \times 2^E ~~~~ \text{con} ~~~~ E \in [-1, 1]$$

$$ 2 \times 1 \times 2 \times 3 + 1 = 13$$

Cuál es la distribución en la línea real?

```python
d_1_values = [1]
d_2_values = [0, 1]
E_values = [1, 0, -1]

fig = plt.figure(figsize=(10.0, 1.0))
axes = fig.add_subplot(1, 1, 1)

for E in E_values:
    for d1 in d_1_values:
        for d2 in d_2_values:
            axes.plot( (d1 + d2 * 0.5) * 2**E, 0.0, 'r+', markersize=20)
            axes.plot(-(d1 + d2 * 0.5) * 2**E, 0.0, 'r+', markersize=20)

axes.plot(0.0, 0.0, 'r+', markersize=20)
axes.plot([-4.5, 4.5], [0.0, 0.0], 'k')

axes.set_title("Distribución de Valores")
axes.set_yticks([])
axes.set_xlabel("x")
axes.set_ylabel("")
axes.set_xlim([-3.5, 3.5])
plt.show()
```

Cuáles son los límites superior (*overflow*) e inferior (*underflow*)?

- El menor número que puede ser representado (*underflow*) es: $1.0 \times 2^{-1} = 0.5$

- El mayor número que puede ser representado (*overflow*) es:  $1.1 \times 2^1 = 3$

Observe que estos números son en sistema binario.

Una rápida regla de oro:

$$2^3 2^2 2^1 2^0 . 2^{-1} 2^{-2} 2^{-3}$$

corresponde a

8s, 4s, 2s, 1s . mitades, cuartos, octavos, $\ldots$

### Sistema real - IEEE 754 sistema binario de punto flotante

#### Precisión simple

- Almacenamiento total es de 32 bits

- Exponente de 8 bits $\Rightarrow E \in [-126, 127]$

- Fracción 23 bits ($p = 24$)

```
s EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF
0 1      8 9                     31
```

Overflow $= 2^{127} \approx 3.4 \times 10^{38}$

Underflow $= 2^{-126} \approx 1.2 \times 10^{-38}$

$\epsilon_{\text{machine}} = 2^{-23} \approx 1.2 \times 10^{-7}$

#### Precisión doble

- Almacenamiento total asignado es 64 bits

- Exponenete de 11 bits $\Rightarrow E \in [-1022, 1024]$

- Fracción de 52 bits ($p = 53$)

```
s EEEEEEEEEE FFFFFFFFFF FFFFFFFFFF FFFFFFFFFF FFFFFFFFFF FFFFFFFFFF FF
0 1       11 12                                                      63
```
Overflow $= 2^{1024} \approx 1.8 \times 10^{308}$

Underflow $= 2^{-1022} \approx 2.2 \times 10^{-308}$

$\epsilon_{\text{machine}} = 2^{-52} \approx 2.2 \times 10^{-16}$

### Acceso de Python a números de la IEEE

Accede a muchos parámetros importantes, como el epsilon de la máquina

```python
import numpy
numpy.finfo(float).eps
```

```python
import numpy
numpy.finfo(float).eps

print(numpy.finfo(numpy.float16))
print(numpy.finfo(numpy.float32))
print(numpy.finfo(float))
print(numpy.finfo(numpy.float128))
```

## Por qué debería importarnos esto?

- Aritmética de punto flotante no es conmutativa o asociativa

- Errores de punto flotante compuestos, No asuma que la precisión doble es suficiente

- Mezclar precisión es muy peligroso

### Ejemplo 1: Aritmética simple

Aritmética simple $\delta < \epsilon_{\text{machine}}$

   $$(1+\delta) - 1 = 1 - 1 = 0$$

   $$1 - 1 + \delta = \delta$$

### Ejemplo 2: Cancelación catastrófica

Miremos qué sucede cuando sumamos dos números $x$ y $y$ cuando $x+y \neq 0$. De hecho, podemos estimar estos límites haciendo un análisis de error. Aquí necesitamos presentar la idea de que cada operación de punto flotante introduce un error tal que

$$
    \text{fl}(x ~\text{op}~ y) = (x ~\text{op}~ y) (1 + \delta)
$$

donde $\text{fl}(\cdot)$ es una función que devuelve la representación de punto flotante de la expresión encerrada, $\text{op}$ es alguna operación (ex. $+, -, \times, /$), y $\delta$ es el error de punto flotante debido a  $\text{op}$.

De vuelta a nuestro problema en cuestión. El error de coma flotante debido a la suma es

$$\text{fl}(x + y) = (x + y) (1 + \delta).$$

Comparando esto con la solución verdadera usando un error relativo tenemos

$$\begin{aligned}
    \frac{(x + y) - \text{fl}(x + y)}{x + y} &= \frac{(x + y) - (x + y) (1 + \delta)}{x + y} = \delta.
\end{aligned}$$

entonces si $\delta = \mathcal{O}(\epsilon_{\text{machine}})$ no estaremos muy preocupados.

Que pasa si consideramos un error de punto flotante en la representación de $x$ y $y$, $x \neq y$, y decimos que $\delta_x$ y $\delta_y$ son la magnitud de los errores en su representación. Asumiremos que esto constituye el error de punto flotante en lugar de estar asociado con la operación en sí.

Dado todo esto, tendríamos

$$\begin{aligned}
    \text{fl}(x + y) &= x (1 + \delta_x) + y (1 + \delta_y) \\
    &= x + y + x \delta_x + y \delta_y \\
    &= (x + y) \left(1 + \frac{x \delta_x + y \delta_y}{x + y}\right)
\end{aligned}$$

Calculando nuevamente el error relativo, tendremos

$$\begin{aligned}
    \frac{x + y - (x + y) \left(1 + \frac{x \delta_x + y \delta_y}{x + y}\right)}{x + y} &= 1 - \left(1 + \frac{x \delta_x + y \delta_y}{x + y}\right) \\
    &= \frac{x}{x + y} \delta_x + \frac{y}{x + y} \delta_y \\
    &= \frac{1}{x + y} (x \delta_x + y \delta_y)
\end{aligned}$$

Lo importante aquí es que ahora el error depende de los valores de $x$ y $y$, y más importante aún, su suma. De particular preocupación es el tamaño relativo de $x + y$. A medida que se acerca a cero en relación con las magnitudes de $x$ y $y$, el error podría ser arbitrariamente grande. Esto se conoce como ***cancelación catastrófica***.

```python
dx = numpy.array([10**(-n) for n in range(1, 16)])
x = 1.0 + dx
y = -numpy.ones(x.shape)
error = numpy.abs(x + y - dx) / (dx)

fig = plt.figure()
fig.set_figwidth(fig.get_figwidth() * 2)

axes = fig.add_subplot(1, 2, 1)
axes.loglog(dx, x + y, 'o-')
axes.set_xlabel("$\Delta x$")
axes.set_ylabel("$x + y$")
axes.set_title("$\Delta x$ vs. $x+y$")

axes = fig.add_subplot(1, 2, 2)
axes.loglog(dx, error, 'o-')
axes.set_xlabel("$\Delta x$")
axes.set_ylabel("$|x + y - \Delta x| / \Delta x$")
axes.set_title("Diferencia entre $x$ y $y$ vs. Error relativo")

plt.show()
```

### Ejemplo 3: Evaluación de una función

Considere la función

$$
    f(x) = \frac{1 - \cos x}{x^2}
$$

con $x\in[-10^{-4}, 10^{-4}]$.

Tomando el límite cuando $x \rightarrow 0$ podemos ver qué comportamiento esperaríamos ver al evaluar esta función:

$$
    \lim_{x \rightarrow 0} \frac{1 - \cos x}{x^2} = \lim_{x \rightarrow 0} \frac{\sin x}{2 x} = \lim_{x \rightarrow 0} \frac{\cos x}{2} = \frac{1}{2}.
$$

¿Qué hace la representación de punto flotante?

```python
x = numpy.linspace(-1e-3, 1e-3, 100, dtype=numpy.float32)
error = (0.5 - (1.0 - numpy.cos(x)) / x**2) / 0.5

fig = plt.figure()
axes = fig.add_subplot(1, 1, 1)
axes.plot(x, error, 'o')
axes.set_xlabel("x")
axes.set_ylabel("Error Relativo")
```

### Ejemplo 4: Evaluación de un Polinomio

 $$f(x) = x^7 - 7x^6 + 21 x^5 - 35 x^4 + 35x^3-21x^2 + 7x - 1$$

```python
x = numpy.linspace(0.988, 1.012, 1000, dtype=numpy.float16)
y = x**7 - 7.0 * x**6 + 21.0 * x**5 - 35.0 * x**4 + 35.0 * x**3 - 21.0 * x**2 + 7.0 * x - 1.0

fig = plt.figure()
axes = fig.add_subplot(1, 1, 1)
axes.plot(x, y, 'r')
axes.set_xlabel("x")
axes.set_ylabel("y")
axes.set_ylim((-0.1, 0.1))
axes.set_xlim((x[0], x[-1]))
plt.show()
```

### Ejemplo 5: Evaluación de una función racional

Calcule $f(x) = x + 1$ por la función $$F(x) = \frac{x^2 - 1}{x - 1}$$

¿Cuál comportamiento esperarías encontrar?

```python
x = numpy.linspace(0.5, 1.5, 101, dtype=numpy.float16)
f_hat = (x**2 - 1.0) / (x - 1.0)

fig = plt.figure()
axes = fig.add_subplot(1, 1, 1)
axes.plot(x, numpy.abs(f_hat - (x + 1.0)))
axes.set_xlabel("$x$")
axes.set_ylabel("Error Absoluto")
plt.show()
```

## Combinación de error

En general, nos debemos ocupar de la combinación de error de truncamiento con el error de punto flotante.

- Error de Truncamiento: errores que surgen de la aproximación de una función, truncamiento de una serie.

$$\sin x \approx x - \frac{x^3}{3!} + \frac{x^5}{5!} + O(x^7)$$

- Error de punto flotante: errores derivados de la aproximación de números reales con números de precisión finita

$$\pi \approx 3.14$$

o $\frac{1}{3} \approx 0.333333333$ en decimal, los resultados forman un número finito de registros para representar cada número.

### Ejemplo 1:

Considere la aproximación de diferencias finitas donde $f(x) = e^x$ y estamos evaluando en $x=1$

$$f'(x) \approx \frac{f(x + \Delta x) - f(x)}{\Delta x}$$

Compare el error entre disminuir $\Delta x$ y la verdadera solucion $f'(1) = e$

```python
delta_x = numpy.linspace(1e-20, 5.0, 100)
delta_x = numpy.array([2.0**(-n) for n in range(1, 60)])
x = 1.0
f_hat_1 = (numpy.exp(x + delta_x) - numpy.exp(x)) / (delta_x)
f_hat_2 = (numpy.exp(x + delta_x) - numpy.exp(x - delta_x)) / (2.0 * delta_x)

fig = plt.figure()
axes = fig.add_subplot(1, 1, 1)
axes.loglog(delta_x, numpy.abs(f_hat_1 - numpy.exp(1)), 'o-', label="Unilateral")
axes.loglog(delta_x, numpy.abs(f_hat_2 - numpy.exp(1)), 's-', label="Centrado")
axes.legend(loc=3)
axes.set_xlabel("$\Delta x$")
axes.set_ylabel("Error Absoluto")
plt.show()
```

### Ejemplo 2:

Evalúe $e^x$ con la serie de *Taylor*

$$e^x = \sum^\infty_{n=0} \frac{x^n}{n!}$$

podemos elegir $n< \infty$ que puede aproximarse $e^x$ en un rango dado $x \in [a,b]$ tal que el error relativo $E$ satisfaga $E<8 \cdot \varepsilon_{\text{machine}}$?

¿Cuál podría ser una mejor manera de simplemente evaluar el polinomio de Taylor directamente por varios $N$?

```python
import scipy.special

def my_exp(x, N=10):
    value = 0.0
    for n in range(N + 1):
        value += x**n / scipy.special.factorial(n)

    return value

x = numpy.linspace(-2, 2, 100, dtype=numpy.float32)
for N in range(1, 50):
    error = numpy.abs((numpy.exp(x) - my_exp(x, N=N)) / numpy.exp(x))
    if numpy.all(error < 8.0 * numpy.finfo(float).eps):
        break

print(N)

fig = plt.figure()
axes = fig.add_subplot(1, 1, 1)
axes.plot(x, error)
axes.set_xlabel("x")
axes.set_ylabel("Error Relativo")
plt.show()
```

### Ejemplo 3: Error relativo

Digamos que queremos calcular el error relativo de dos valores $x$ y $y$ usando $x$ como valor de normalización

$$
    E = \frac{x - y}{x}
$$
y
$$
    E = 1 - \frac{y}{x}
$$

son equivalentes. En precisión finita, ¿qué forma pidría esperarse que sea más precisa y por qué?

Ejemplo tomado de [blog](https://nickhigham.wordpress.com/2017/08/14/how-and-how-not-to-compute-a-relative-error/) posteado por Nick Higham*

Usando este modelo, la definición original contiene dos operaciones de punto flotante de manera que

$$\begin{aligned}
    E_1 = \text{fl}\left(\frac{x - y}{x}\right) &= \text{fl}(\text{fl}(x - y) / x) \\
    &= \left[ \frac{(x - y) (1 + \delta_+)}{x} \right ] (1 + \delta_/) \\
    &= \frac{x - y}{x}  (1 + \delta_+) (1 + \delta_/)
\end{aligned}$$

Para la otra formulación tenemos

$$\begin{aligned}
    E_2 = \text{fl}\left( 1 - \frac{y}{x} \right ) &= \text{fl}\left(1 - \text{fl}\left(\frac{y}{x}\right) \right) \\
    &= \left(1 - \frac{y}{x} (1 + \delta_/) \right) (1 + \delta_-)
\end{aligned}$$

Si suponemos que todos las $\text{op}$s tienen magnitudes de error similares, entonces podemos simplificar las cosas dejando que

$$
    |\delta_\ast| \le \epsilon.
$$

Para comparar las dos formulaciones, nuevamente usamos el error relativo entre el error relativo verdadero $e_i$ y nuestras versiones calculadas $E_i$

Definición original

$$\begin{aligned}
    \frac{e - E_1}{e} &= \frac{\frac{x - y}{x} - \frac{x - y}{x}  (1 + \delta_+) (1 + \delta_/)}{\frac{x - y}{x}} \\
    &\le 1 - (1 + \epsilon) (1 + \epsilon) = 2 \epsilon + \epsilon^2
\end{aligned}$$

Definición manipulada:

$$\begin{aligned}
    \frac{e - E_2}{e} &= \frac{e - \left[1 - \frac{y}{x}(1 + \delta_/) \right] (1 + \delta_-)}{e} \\
    &= \frac{e - \left[e - \frac{y}{x} \delta_/) \right] (1 + \delta_-)}{e} \\
    &= \frac{e - \left[e + e\delta_- - \frac{y}{x} \delta_/ - \frac{y}{x} \delta_/ \delta_-)) \right] }{e} \\
    &= - \delta_- + \frac{1}{e} \frac{y}{x} \left(\delta_/ + \delta_/ \delta_- \right) \\
    &= - \delta_- + \frac{1 -e}{e} \left(\delta_/ + \delta_/ \delta_- \right) \\
    &\le \epsilon + \left |\frac{1 - e}{e}\right | (\epsilon + \epsilon^2)
\end{aligned}$$

Vemos entonces que nuestro error de punto flotante dependerá de la magnitud relativa de $e$

```python
# Based on the code by Nick Higham
# https://gist.github.com/higham/6f2ce1cdde0aae83697bca8577d22a6e
# Compares relative error formulations using single precision and compared to double precision

N = 501    # Note: Use 501 instead of 500 to avoid the zero value
d = numpy.finfo(numpy.float32).eps * 1e4
a = 3.0
x = a * numpy.ones(N, dtype=numpy.float32)
y = [x[i] + numpy.multiply((i - numpy.divide(N, 2.0, dtype=numpy.float32)), d, dtype=numpy.float32) for i in range(N)]

# Compute errors and "true" error
relative_error = numpy.empty((2, N), dtype=numpy.float32)
relative_error[0, :] = numpy.abs(x - y) / x
relative_error[1, :] = numpy.abs(1.0 - y / x)
exact = numpy.abs( (numpy.float64(x) - numpy.float64(y)) / numpy.float64(x))

# Compute differences between error calculations
error = numpy.empty((2, N))
for i in range(2):
    error[i, :] = numpy.abs((relative_error[i, :] - exact) / numpy.abs(exact))

fig = plt.figure()
axes = fig.add_subplot(1, 1, 1)
axes.semilogy(y, error[0, :], '.', markersize=10, label="$|x-y|/|x|$")
axes.semilogy(y, error[1, :], '.', markersize=10, label="$|1-y/x|$")

axes.grid(True)
axes.set_xlabel("y")
axes.set_ylabel("Error Relativo")
axes.set_xlim((numpy.min(y), numpy.max(y)))
axes.set_ylim((5e-9, numpy.max(error[1, :])))
axes.set_title("Comparasión Error Relativo")
axes.legend()
plt.show()
```

Algunos enlaces de utilidad con respecto al punto flotante IEEE:

- [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)

- [IEEE 754 Floating Point Calculator](http://babbage.cs.qc.edu/courses/cs341/IEEE-754.html)

- [Numerical Computing with IEEE Floating Point Arithmetic](http://epubs.siam.org/doi/book/10.1137/1.9780898718072)

## Operaciones de conteo

- ***Error de truncamiento:*** *¿Por qué no usar más términos en la serie de Taylor?*

- ***Error de punto flotante:*** *¿Por qué no utilizar la mayor precisión posible?*

### Ejemplo 1: Multiplicación matriz - vector

Sea $A, B \in \mathbb{R}^{N \times N}$ y $x \in \mathbb{R}^N$.

1. Cuenta el número aproximado de operaciones que tomará para calcular $Ax$

2. Hacer lo mismo para $AB$

***Producto Matriz-vector:*** Definiendo $[A]_i$ como la $i$-ésima fila de $A$ y $A_{ij}$ como la $i$,$j$-ésima entrada entonces

$$
    A x = \sum^N_{i=1} [A]_i \cdot x = \sum^N_{i=1} \sum^N_{j=1} A_{ij} x_j
$$

Tomando un caso en particular, siendo $N=3$, entonces la operación de conteo es

$$
    A x = [A]_1 \cdot v + [A]_2 \cdot v + [A]_3 \cdot v = \begin{bmatrix}
        A_{11} \times v_1 + A_{12} \times v_2 + A_{13} \times v_3 \\
        A_{21} \times v_1 + A_{22} \times v_2 + A_{23} \times v_3 \\
        A_{31} \times v_1 + A_{32} \times v_2 + A_{33} \times v_3
    \end{bmatrix}
$$

Esto son 15 operaciones (6 sumas y 9 multiplicaciones)

Tomando otro caso, siendo $N=4$, entonces el conteo de operaciones es:

$$
    A x = [A]_1 \cdot v + [A]_2 \cdot v + [A]_3 \cdot v = \begin{bmatrix}
        A_{11} \times v_1 + A_{12} \times v_2 + A_{13} \times v_3 + A_{14} \times v_4 \\
        A_{21} \times v_1 + A_{22} \times v_2 + A_{23} \times v_3 + A_{24} \times v_4 \\
        A_{31} \times v_1 + A_{32} \times v_2 + A_{33} \times v_3 + A_{34} \times v_4 \\
        A_{41} \times v_1 + A_{42} \times v_2 + A_{43} \times v_3 + A_{44} \times v_4 \\
    \end{bmatrix}
$$

Esto lleva a 28 operaciones (12 sumas y 16 multiplicaciones).

Generalizando, hay $N^2$ mutiplicaciones y $N(N-1)$ sumas para un total de

$$
    \text{operaciones} = N (N - 1) + N^2 = \mathcal{O}(N^2).
$$

***Producto Matriz-Matriz ($AB$):*** Definiendo $[B]_j$ como la $j$-ésima columna de $B$ entonces

$$
    (A B)_{ij} = \sum^N_{i=1} \sum^N_{j=1} [A]_i \cdot [B]_j
$$

El producto interno de dos vectores es representado por

$$
    a \cdot b = \sum^N_{i=1} a_i b_i
$$

conduce a $\mathcal{O}(3N)$ operaciones. Como hay $N^2$ entradas en la matriz resultante, tendríamos $\mathcal{O}(N^3)$ operaciones

Existen métodos para realizar la multiplicación matriz - matriz más rápido. En la siguiente figura vemos una colección de algoritmos a lo largo del tiempo que han podido limitar el número de operaciones en ciertas circunstancias
$$
    \mathcal{O}(N^\omega)
$$

### Ejemplo 2: Método de Horner para evaluar polinomios

Dado

$$P_N(x) = a_0 + a_1 x + a_2 x^2 + \ldots + a_N x^N$$

o

$$P_N(x) = p_1 x^N + p_2 x^{N-1} + p_3 x^{N-2} + \ldots + p_{N+1}$$

queremos encontrar la mejor vía para evaluar $P_N(x)$

Primero considere dos vías para escribir $P_3$

$$ P_3(x) = p_1 x^3 + p_2 x^2 + p_3 x + p_4$$

y usando multiplicación anidada

$$ P_3(x) = ((p_1 x + p_2) x + p_3) x + p_4$$

Considere cuántas operaciones se necesitan para cada...

$$ P_3(x) = p_1 x^3 + p_2 x^2 + p_3 x + p_4$$

$$P_3(x) = \overbrace{p_1 \cdot x \cdot x \cdot x}^3 + \overbrace{p_2 \cdot x \cdot x}^2 + \overbrace{p_3 \cdot x}^1 + p_4$$

Sumando todas las operaciones, en general podemos pensar en esto como una pirámide

podemos estimar de esta manera que el algoritmo escrito de esta manera tomará aproximadamente $\mathcal{O}(N^2/2)$ operaciones para completar.

Mirando nuetros otros medios de evaluación

$$ P_3(x) = ((p_1 x + p_2) x + p_3) x + p_4$$

Aquí encontramos que el método es $\mathcal{O}(N)$ (el 2 generalmente se ignora en estos casos). Lo importante es que la primera evaluación es $\mathcal{O}(N^2)$ y la segunda $\mathcal{O}(N)$!

### Algoritmo

Complete la función e implemente el método de *Horner*

```python
def eval_poly(p, x):
    """Evaluates polynomial given coefficients p at x

    Function to evaluate a polynomial in order N operations.  The polynomial is defined as

    P(x) = p[0] x**n + p[1] x**(n-1) + ... + p[n-1] x + p[n]

    The value x should be a float.
    """
    pass
```

```python
def eval_poly(p, x):
    """Evaluates polynomial given coefficients p at x

    Function to evaluate a polynomial in order N operations.  The polynomial is defined as

    P(x) = p[0] x**n + p[1] x**(n-1) + ... + p[n-1] x + p[n]

    The value x should be a float.
    """
    ### ADD CODE HERE
    pass
```

```python
# Scalar version
def eval_poly(p, x):
    """Evaluates polynomial given coefficients p at x

    Function to evaluate a polynomial in order N operations.  The polynomial is defined as

    P(x) = p[0] x**n + p[1] x**(n-1) + ... + p[n-1] x + p[n]

    The value x should be a float.
    """

    y = p[0]
    for coefficient in p[1:]:
        y = y * x + coefficient

    return y

# Vectorized version
def eval_poly(p, x):
    """Evaluates polynomial given coefficients p at x

    Function to evaluate a polynomial in order N operations.  The polynomial is defined as

    P(x) = p[0] x**n + p[1] x**(n-1) + ... + p[n-1] x + p[n]

    The value x can by a NumPy ndarray.
    """

    y = numpy.ones(x.shape) * p[0]
    for coefficient in p[1:]:
        y = y * x + coefficient

    return y

p = [1, -3, 10, 4, 5, 5]
x = numpy.linspace(-10, 10, 100)
plt.plot(x, eval_poly(p, x))
plt.show()
```

```python

```


# Example of DOV search methods for CPT measurements (sonderingen)

[](https://mybinder.org/v2/gh/DOV-Vlaanderen/pydov/master?filepath=docs%2Fnotebooks%2Fsearch_sonderingen.ipynb)

## Use cases explained below
* Get CPT measurements in a bounding box
* Get CPT measurements with specific properties
* Get CPT measurements in a bounding box based on specific properties
* Select CPT measurements in a municipality and return depth
* Get CPT measurements based on fields not available in the standard output dataframe
* Get CPT measurements data, returning fields not available in the standard output dataframe
* Get CPT measurements in a municipality and where groundwater related data are available

```python
%matplotlib inline
import inspect, sys
```

```python
import pydov
```

## Get information about the datatype 'Sondering'

```python
from pydov.search.sondering import SonderingSearch
sondering = SonderingSearch()
```

A description is provided for the 'Sondering' datatype:

```python
sondering.get_description()
```

    'In DOV worden de resultaten van sonderingen ter beschikking gesteld. Bij het uitvoeren van de sondering wordt een sondeerpunt met conus bij middel van buizen statisch de grond ingedrukt. Continu of met bepaalde diepte-intervallen wordt de weerstand aan de conuspunt, de plaatselijke wrijvingsweerstand en/of de totale indringingsweerstand opgemeten. Eventueel kan aanvullend de waterspanning in de grond rond de conus tijdens de sondering worden opgemeten met een waterspanningsmeter. Het op diepte drukken van de sondeerbuizen gebeurt met een indrukapparaat. De nodige reactie voor het indrukken van de buizen wordt geleverd door een verankering en/of door het gewicht van de sondeerwagen. De totale indrukcapaciteit varieert van 25 kN tot 250 kN, afhankelijk van apparaat en opstellingswijze.'

The different fields that are available for objects of the 'Sondering' datatype can be requested with the get_fields() method:

```python
fields = sondering.get_fields()

# print available fields
for f in fields.values():
    print(f['name'])
```

    id
    sondeernummer
    pkey_sondering
    weerstandsdiagram
    meetreeks
    x
    y
    start_sondering_mtaw
    gemeente
    diepte_sondering_van
    diepte_sondering_tot
    datum_aanvang
    uitvoerder
    conus
    sondeermethode
    apparaat
    informele_stratigrafie
    formele_stratigrafie
    hydrogeologische_stratigrafie
    opdrachten
    datum_gw_meting
    diepte_gw_m
    z
    qc
    Qt
    fs
    u
    i

You can get more information of a field by requesting it from the fields dictionary:
* *name*: name of the field
* *definition*: definition of this field
* *cost*: currently this is either 1 or 10, depending on the datasource of the field. It is an indication of the expected time it will take to retrieve this field in the output dataframe.
* *notnull*: whether the field is mandatory or not
* *type*: datatype of the values of this field

```python
fields['diepte_sondering_tot']
```

    {'name': 'diepte_sondering_tot',
     'definition': 'Maximumdiepte van de sondering ten opzichte van het aanvangspeil, in meter.',
     'type': 'float',
     'notnull': False,
     'query': True,
     'cost': 1}

Optionally, if the values of the field have a specific domain the possible values are listed as *values*:

```python
fields['conus']['values']
```

    {'E': None, 'M1': None, 'M2': None, 'M4': None, 'U': None, 'onbekend': None}

## Example use cases

### Get CPT measurements in a bounding box

Get data for all the CPT measurements that are geographically located within the bounds of the specified box.

The coordinates are in the Belgian Lambert72 (EPSG:31370) coordinate system and are given in the order of lower left x, lower left y, upper right x, upper right y.

```python
from pydov.util.location import Within, Box

df = sondering.search(location=Within(Box(152999, 206930, 153050, 207935)))
df.head()
```

    [000/001] .

      pkey_sondering
      sondeernummer
      x
      y
      start_sondering_mtaw
      diepte_sondering_van
      diepte_sondering_tot
      datum_aanvang
      uitvoerder
      sondeermethode
      apparaat
      datum_gw_meting
      diepte_gw_m
      z
      qc
      Qt
      fs
      u
      i

      0
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-72/555-SXVIII
      153008.0
      206985.0
      15.8
      0.0
      36.0
      1973-03-21
      Rijksinstituut voor Grondmechanica
      discontinu mechanisch
      100KN
      NaN
      NaN
      0.2
      1.6
      2.06
      NaN
      NaN
      NaN

      1
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-72/555-SXVIII
      153008.0
      206985.0
      15.8
      0.0
      36.0
      1973-03-21
      Rijksinstituut voor Grondmechanica
      discontinu mechanisch
      100KN
      NaN
      NaN
      0.4
      3.6
      4.26
      NaN
      NaN
      NaN

      2
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-72/555-SXVIII
      153008.0
      206985.0
      15.8
      0.0
      36.0
      1973-03-21
      Rijksinstituut voor Grondmechanica
      discontinu mechanisch
      100KN
      NaN
      NaN
      0.6
      2.6
      3.46
      NaN
      NaN
      NaN

      3
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-72/555-SXVIII
      153008.0
      206985.0
      15.8
      0.0
      36.0
      1973-03-21
      Rijksinstituut voor Grondmechanica
      discontinu mechanisch
      100KN
      NaN
      NaN
      0.8
      4.0
      5.66
      NaN
      NaN
      NaN

      4
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-72/555-SXVIII
      153008.0
      206985.0
      15.8
      0.0
      36.0
      1973-03-21
      Rijksinstituut voor Grondmechanica
      discontinu mechanisch
      100KN
      NaN
      NaN
      1.0
      3.0
      6.53
      NaN
      NaN
      NaN

The dataframe contains one CPT measurement where multiple measurement points. The available data are flattened to represent unique attributes per row of the dataframe.

Using the *pkey_sondering* field one can request the details of this borehole in a webbrowser:

```python
for pkey_sondering in set(df.pkey_sondering):
    print(pkey_sondering)
```

    https://www.dov.vlaanderen.be/data/sondering/1973-016812

### Get CPT measurements with specific properties

Next to querying CPT based on their geographic location within a bounding box, we can also search for CPT measurements matching a specific set of properties. For this we can build a query using a combination of the 'Sondering' fields and operators provided by the WFS protocol.

A list of possible operators can be found below:

```python
[i for i,j in inspect.getmembers(sys.modules['owslib.fes'], inspect.isclass) if 'Property' in i]
```

    ['PropertyIsBetween',
     'PropertyIsEqualTo',
     'PropertyIsGreaterThan',
     'PropertyIsGreaterThanOrEqualTo',
     'PropertyIsLessThan',
     'PropertyIsLessThanOrEqualTo',
     'PropertyIsLike',
     'PropertyIsNotEqualTo',
     'PropertyIsNull',
     'SortProperty']

In this example we build a query using the *PropertyIsEqualTo* operator to find all CPT measuremetns that are within the community (gemeente) of 'Herstappe':

```python
from owslib.fes import PropertyIsEqualTo

query = PropertyIsEqualTo(propertyname='gemeente',
                          literal='Elsene')
df = sondering.search(query=query)

df.head()
```

    [000/029] .............................

      pkey_sondering
      sondeernummer
      x
      y
      start_sondering_mtaw
      diepte_sondering_van
      diepte_sondering_tot
      datum_aanvang
      uitvoerder
      sondeermethode
      apparaat
      datum_gw_meting
      diepte_gw_m
      z
      qc
      Qt
      fs
      u
      i

      0
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-75/194-S1
      150310.0
      169796.0
      56.3
      0.0
      4.5
      1975-05-20
      Rijksinstituut voor Grondmechanica
      discontinu mechanisch
      25KN
      NaN
      1.97
      1.0
      3.3
      NaN
      NaN
      NaN
      NaN

      1
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-75/194-S1
      150310.0
      169796.0
      56.3
      0.0
      4.5
      1975-05-20
      Rijksinstituut voor Grondmechanica
      discontinu mechanisch
      25KN
      NaN
      1.97
      1.1
      2.9
      NaN
      NaN
      NaN
      NaN

      2
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-75/194-S1
      150310.0
      169796.0
      56.3
      0.0
      4.5
      1975-05-20
      Rijksinstituut voor Grondmechanica
      discontinu mechanisch
      25KN
      NaN
      1.97
      1.2
      2.7
      NaN
      NaN
      NaN
      NaN

      3
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-75/194-S1
      150310.0
      169796.0
      56.3
      0.0
      4.5
      1975-05-20
      Rijksinstituut voor Grondmechanica
      discontinu mechanisch
      25KN
      NaN
      1.97
      1.3
      2.4
      NaN
      NaN
      NaN
      NaN

      4
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-75/194-S1
      150310.0
      169796.0
      56.3
      0.0
      4.5
      1975-05-20
      Rijksinstituut voor Grondmechanica
      discontinu mechanisch
      25KN
      NaN
      1.97
      1.4
      3.6
      NaN
      NaN
      NaN
      NaN

Once again we can use the *pkey_sondering* as a permanent link to the information of these CPT measurements:

```python
for pkey_sondering in set(df.pkey_sondering):
    print(pkey_sondering)
```

    https://www.dov.vlaanderen.be/data/sondering/1974-016926
    https://www.dov.vlaanderen.be/data/sondering/1976-030150
    https://www.dov.vlaanderen.be/data/sondering/1971-023321
    https://www.dov.vlaanderen.be/data/sondering/1976-013900
    https://www.dov.vlaanderen.be/data/sondering/1976-014640
    https://www.dov.vlaanderen.be/data/sondering/1974-016927
    https://www.dov.vlaanderen.be/data/sondering/1992-000338
    https://www.dov.vlaanderen.be/data/sondering/1971-022777
    https://www.dov.vlaanderen.be/data/sondering/1980-024719
    https://www.dov.vlaanderen.be/data/sondering/1976-030128
    https://www.dov.vlaanderen.be/data/sondering/1971-023323
    https://www.dov.vlaanderen.be/data/sondering/1980-024720
    https://www.dov.vlaanderen.be/data/sondering/1971-022775
    https://www.dov.vlaanderen.be/data/sondering/1992-000339
    https://www.dov.vlaanderen.be/data/sondering/1992-000335
    https://www.dov.vlaanderen.be/data/sondering/1975-014063
    https://www.dov.vlaanderen.be/data/sondering/1971-023091
    https://www.dov.vlaanderen.be/data/sondering/1976-030148
    https://www.dov.vlaanderen.be/data/sondering/1976-030140
    https://www.dov.vlaanderen.be/data/sondering/1971-023320
    https://www.dov.vlaanderen.be/data/sondering/1971-023322
    https://www.dov.vlaanderen.be/data/sondering/1971-022776
    https://www.dov.vlaanderen.be/data/sondering/1976-013899
    https://www.dov.vlaanderen.be/data/sondering/1976-014638
    https://www.dov.vlaanderen.be/data/sondering/1975-014064
    https://www.dov.vlaanderen.be/data/sondering/1976-013898
    https://www.dov.vlaanderen.be/data/sondering/1992-000337
    https://www.dov.vlaanderen.be/data/sondering/1971-023319
    https://www.dov.vlaanderen.be/data/sondering/1992-000336

### Get CPT measurements in a bounding box based on specific properties

We can combine a query on attributes with a query on geographic location to get the CPT measurements within a bounding box that have specific properties.

The following example requests the CPT measurements with a depth greater than or equal to 2000 meters within the given bounding box.

(Note that the datatype of the *literal* parameter should be a string, regardless of the datatype of this field in the output dataframe.)

```python
from owslib.fes import PropertyIsGreaterThanOrEqualTo

query = PropertyIsGreaterThanOrEqualTo(
            propertyname='diepte_sondering_tot',
            literal='20')

df = sondering.search(
    location=Within(Box(200000, 211000, 205000, 214000)),
    query=query
    )

df.head()
```

    [000/021] .....................

      pkey_sondering
      sondeernummer
      x
      y
      start_sondering_mtaw
      diepte_sondering_van
      diepte_sondering_tot
      datum_aanvang
      uitvoerder
      sondeermethode
      apparaat
      datum_gw_meting
      diepte_gw_m
      z
      qc
      Qt
      fs
      u
      i

      0
      https://www.dov.vlaanderen.be/data/sondering/2...
      GEO-10/095-S1
      200030.2
      212577.5
      26.58
      1.25
      20.65
      2010-08-30
      VO - Afdeling Geotechniek
      continu elektrisch
      200kN - TRACK-TRUCK
      2010-08-30 12:50:00
      1.45
      1.30
      1.22
      NaN
      1.0
      NaN
      0.8

      1
      https://www.dov.vlaanderen.be/data/sondering/2...
      GEO-10/095-S1
      200030.2
      212577.5
      26.58
      1.25
      20.65
      2010-08-30
      VO - Afdeling Geotechniek
      continu elektrisch
      200kN - TRACK-TRUCK
      2010-08-30 12:50:00
      1.45
      1.35
      3.19
      NaN
      2.0
      NaN
      1.0

      2
      https://www.dov.vlaanderen.be/data/sondering/2...
      GEO-10/095-S1
      200030.2
      212577.5
      26.58
      1.25
      20.65
      2010-08-30
      VO - Afdeling Geotechniek
      continu elektrisch
      200kN - TRACK-TRUCK
      2010-08-30 12:50:00
      1.45
      1.40
      7.21
      NaN
      63.0
      NaN
      1.2

      3
      https://www.dov.vlaanderen.be/data/sondering/2...
      GEO-10/095-S1
      200030.2
      212577.5
      26.58
      1.25
      20.65
      2010-08-30
      VO - Afdeling Geotechniek
      continu elektrisch
      200kN - TRACK-TRUCK
      2010-08-30 12:50:00
      1.45
      1.45
      12.75
      NaN
      138.0
      NaN
      1.2

      4
      https://www.dov.vlaanderen.be/data/sondering/2...
      GEO-10/095-S1
      200030.2
      212577.5
      26.58
      1.25
      20.65
      2010-08-30
      VO - Afdeling Geotechniek
      continu elektrisch
      200kN - TRACK-TRUCK
      2010-08-30 12:50:00
      1.45
      1.50
      15.26
      NaN
      143.0
      NaN
      1.4

We can look at one of the CPT measurements in a webbrowser using its *pkey_sondering*:

```python
for pkey_sondering in set(df.pkey_sondering):
    print(pkey_sondering)
```

    https://www.dov.vlaanderen.be/data/sondering/2015-055496
    https://www.dov.vlaanderen.be/data/sondering/2008-077545
    https://www.dov.vlaanderen.be/data/sondering/2008-077592
    https://www.dov.vlaanderen.be/data/sondering/2007-049201
    https://www.dov.vlaanderen.be/data/sondering/2008-077566
    https://www.dov.vlaanderen.be/data/sondering/2009-000053
    https://www.dov.vlaanderen.be/data/sondering/2009-000052
    https://www.dov.vlaanderen.be/data/sondering/2008-077556
    https://www.dov.vlaanderen.be/data/sondering/2010-062407
    https://www.dov.vlaanderen.be/data/sondering/2008-077579
    https://www.dov.vlaanderen.be/data/sondering/2008-077580
    https://www.dov.vlaanderen.be/data/sondering/2008-077564
    https://www.dov.vlaanderen.be/data/sondering/2008-077581
    https://www.dov.vlaanderen.be/data/sondering/2008-077577
    https://www.dov.vlaanderen.be/data/sondering/2008-077591
    https://www.dov.vlaanderen.be/data/sondering/2009-000054
    https://www.dov.vlaanderen.be/data/sondering/2015-054995
    https://www.dov.vlaanderen.be/data/sondering/2015-054999
    https://www.dov.vlaanderen.be/data/sondering/2007-049200
    https://www.dov.vlaanderen.be/data/sondering/2008-077565
    https://www.dov.vlaanderen.be/data/sondering/2008-077557

### Select CPT measurements in a municipality and return depth

We can limit the columns in the output dataframe by specifying the *return_fields* parameter in our search.

In this example we query all the CPT measurements in the city of Ghent and return their depth:

```python
query = PropertyIsEqualTo(propertyname='gemeente',
                          literal='Gent')
df = sondering.search(query=query,
                      return_fields=('diepte_sondering_tot',))
df.head()
```

      diepte_sondering_tot

      0
      2.7

      1
      1.4

      2
      7.6

      3
      11.5

      4
      18.6

```python
df.describe()
```

      diepte_sondering_tot

      count
      3589.000000

      mean
      18.509772

      std
      8.498644

      min
      1.000000

      25%
      11.400000

      50%
      18.800000

      75%
      24.600000

      max
      52.600000

```python
ax = df.boxplot()
ax.set_title('Distribution depth CPT measurements in Ghent');
ax.set_ylabel("depth (m)")
```

### Get CPT measurements based on fields not available in the standard output dataframe

To keep the output dataframe size acceptable, not all available WFS fields are included in the standard output. However, one can use this information to select CPT measurements as illustrated below.

For example, make a selection of the CPT measurements in municipality the of Antwerp, using a conustype 'U':

```python
from owslib.fes import And

query = And([PropertyIsEqualTo(propertyname='gemeente',
                               literal='Antwerpen'),
             PropertyIsEqualTo(propertyname='conus',
                               literal='U')]
            )
df = sondering.search(query=query,
                      return_fields=('pkey_sondering', 'sondeernummer', 'x', 'y', 'diepte_sondering_tot', 'datum_aanvang'))
df.head()
```

      pkey_sondering
      sondeernummer
      x
      y
      diepte_sondering_tot
      datum_aanvang

      0
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-93/023-SII-E
      152740.0
      215493.0
      29.70
      1993-03-02

      1
      https://www.dov.vlaanderen.be/data/sondering/2...
      GEO-02/111-S1
      150347.3
      214036.4
      29.95
      2002-12-17

      2
      https://www.dov.vlaanderen.be/data/sondering/2...
      GEO-04/123-SKD4-E
      146437.7
      222317.5
      4.45
      2004-07-12

      3
      https://www.dov.vlaanderen.be/data/sondering/2...
      GEO-04/123-SKD6-E
      146523.9
      222379.7
      7.40
      2004-07-14

      4
      https://www.dov.vlaanderen.be/data/sondering/2...
      GEO-04/123-SKD5-E
      146493.4
      222298.8
      1.65
      2004-07-16

### Get CPT data, returning fields not available in the standard output dataframe

As denoted in the previous example, not all available fields are available in the default output frame to keep its size limited. However, you can request any available field by including it in the *return_fields* parameter of the search:

```python
query = And([PropertyIsEqualTo(propertyname='gemeente', literal='Gent'),
             PropertyIsEqualTo(propertyname='conus', literal='U')])

df = sondering.search(query=query,
                      return_fields=('pkey_sondering', 'sondeernummer', 'diepte_sondering_tot',
                                     'conus', 'x', 'y'))

df.head()
```

      pkey_sondering
      sondeernummer
      diepte_sondering_tot
      conus
      x
      y

      0
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SV
      33.80
      U
      110241.6
      204692.2

      1
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SI
      15.65
      U
      110062.5
      205051.4

      2
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SII
      26.50
      U
      110107.0
      204965.3

      3
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SIII
      16.50
      U
      110152.4
      204876.1

      4
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SIV
      16.70
      U
      110197.8
      204787.0

```python
df
```

      pkey_sondering
      sondeernummer
      diepte_sondering_tot
      conus
      x
      y

      0
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SV
      33.80
      U
      110241.6
      204692.2

      1
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SI
      15.65
      U
      110062.5
      205051.4

      2
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SII
      26.50
      U
      110107.0
      204965.3

      3
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SIII
      16.50
      U
      110152.4
      204876.1

      4
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SIV
      16.70
      U
      110197.8
      204787.0

      5
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SIX
      27.60
      U
      110479.5
      205240.7

      6
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SVI
      16.80
      U
      110288.5
      204608.8

      7
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SVII
      26.70
      U
      110334.3
      204519.8

      8
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SX
      27.50
      U
      110685.0
      204845.5

      9
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SXI
      25.60
      U
      109941.5
      204346.9

      10
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/020-SXII
      26.50
      U
      110412.2
      204398.1

      11
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/096-SIX(CPT9)
      17.60
      U
      105018.0
      190472.0

      12
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/096-SVII(CPT7)
      26.05
      U
      105046.0
      190550.0

      13
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-94/096-SVIII(CPT8)
      24.75
      U
      104997.0
      190521.0

      14
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-97/002-S2
      29.90
      U
      105376.6
      189104.3

      15
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-97/002-S3
      5.90
      U
      105391.3
      189083.7

      16
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-97/002-S1
      30.60
      U
      105399.3
      189065.2

      17
      https://www.dov.vlaanderen.be/data/sondering/2...
      GEO-01/162-S1
      18.05
      U
      106104.1
      188699.4

      18
      https://www.dov.vlaanderen.be/data/sondering/2...
      GEO-01/162-S2
      17.30
      U
      106045.3
      188708.4

      19
      https://www.dov.vlaanderen.be/data/sondering/2...
      GEO-01/162-S3
      18.70
      U
      106100.5
      188743.8

      20
      https://www.dov.vlaanderen.be/data/sondering/2...
      GEO-01/162-S5
      17.30
      U
      106130.0
      188712.0

      21
      https://www.dov.vlaanderen.be/data/sondering/2...
      GEO-01/162-S4
      17.00
      U
      106077.5
      188686.0

## Resistivity plot

The data for the reporting of resistivity plots with the online application, see for example [this report](https://www.dov.vlaanderen.be/zoeken-ocdov/proxy-sondering/sondering/1993-001275/rapport/identifygrafiek?outputformaat=PDF), is also accessible with the pydov package. Querying the data for this specific _sondering_:

```python
query = PropertyIsEqualTo(propertyname='pkey_sondering',
                          literal='https://www.dov.vlaanderen.be/data/sondering/1993-001275')
df_sond = sondering.search(query=query)

df_sond.head()
```

    [000/001] .

      pkey_sondering
      sondeernummer
      x
      y
      start_sondering_mtaw
      diepte_sondering_van
      diepte_sondering_tot
      datum_aanvang
      uitvoerder
      sondeermethode
      apparaat
      datum_gw_meting
      diepte_gw_m
      z
      qc
      Qt
      fs
      u
      i

      0
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-93/023-SII-E
      152740.0
      215493.0
      6.25
      0.0
      29.7
      1993-03-02
      MVG - Afdeling Geotechniek
      continu elektrisch
      200KN
      NaN
      NaN
      0.6
      11.60
      NaN
      130.0
      69.0
      NaN

      1
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-93/023-SII-E
      152740.0
      215493.0
      6.25
      0.0
      29.7
      1993-03-02
      MVG - Afdeling Geotechniek
      continu elektrisch
      200KN
      NaN
      NaN
      0.7
      6.30
      NaN
      100.0
      29.0
      NaN

      2
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-93/023-SII-E
      152740.0
      215493.0
      6.25
      0.0
      29.7
      1993-03-02
      MVG - Afdeling Geotechniek
      continu elektrisch
      200KN
      NaN
      NaN
      0.8
      6.22
      NaN
      120.0
      -4.0
      NaN

      3
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-93/023-SII-E
      152740.0
      215493.0
      6.25
      0.0
      29.7
      1993-03-02
      MVG - Afdeling Geotechniek
      continu elektrisch
      200KN
      NaN
      NaN
      0.9
      4.92
      NaN
      120.0
      -48.0
      NaN

      4
      https://www.dov.vlaanderen.be/data/sondering/1...
      GEO-93/023-SII-E
      152740.0
      215493.0
      6.25
      0.0
      29.7
      1993-03-02
      MVG - Afdeling Geotechniek
      continu elektrisch
      200KN
      NaN
      NaN
      1.0
      4.40
      NaN
      80.0
      -35.0
      NaN

We have the depth (`z`) available, together with the measured values for each depth of the variables (in dutch):

* `qc`: Opgemeten waarde van de conusweerstand, uitgedrukt in MPa.
* `Qt`: Opgemeten waarde van de totale weerstand, uitgedrukt in kN.
* `fs`: Opgemeten waarde van de plaatelijke kleefweerstand uitgedrukt in kPa.
* `u`: Opgemeten waarde van de porienwaterspanning, uitgedrukt in kPa.
* `i`: Opgemeten waarde van de inclinatie, uitgedrukt in graden.

To recreate the resistivity plot, we also need the `resistivity number` (wrijvingsgetal `rf`), see [DOV documentation](https://www.dov.vlaanderen.be/page/sonderingen).

\begin{equation}
R_f = \frac{f_s}{q_c}
\end{equation}

**Notice:** $f_s$ is provide in kPa and $q_c$ in MPa.

Adding `rf` to the dataframe:

```python
df_sond["rf"] = df_sond["fs"]/df_sond["qc"]/10
```

Recreate the resistivity plot:

```python
import matplotlib.pyplot as plt
```

```python
def make_patch_spines_invisible(ax):
    ax.set_frame_on(True)
    ax.patch.set_visible(False)
    for sp in ax.spines.values():
        sp.set_visible(False)
```

```python
fig, ax0 = plt.subplots(figsize=(8, 12))

# Prepare the individual axis
ax_qc = ax0.twiny()
ax_fs = ax0.twiny()
ax_u = ax0.twiny()
ax_rf = ax0.twiny()

for i, ax in enumerate([ax_qc, ax_fs, ax_u]):
    ax.spines["top"].set_position(("axes", 1+0.05*(i+1)))
    make_patch_spines_invisible(ax)
    ax.spines["top"].set_visible(True)

# Plot the data on the axis
df_sond.plot(x="rf", y="z", label="rf", ax=ax_rf, color='purple', legend=False)
df_sond.plot(x="qc", y="z", label="qc (MPa)", ax=ax_qc, color='black', legend=False)
df_sond.plot(x="fs", y="z", label="fs (kPa)", ax=ax_fs, color='green', legend=False)
df_sond.plot(x="u", y="z", label="u (kPa)", ax=ax_u, color='red',
        legend=False, xlim=(-100, 300)) # ! 300 is hardocded here for the example

# styling and configuration
ax_rf.xaxis.label.set_color('purple')
ax_fs.xaxis.label.set_color('green')
ax_u.xaxis.label.set_color('red')

ax0.axes.set_visible(False)
ax_qc.axes.yaxis.set_visible(False)
ax_fs.axes.yaxis.set_visible(False)
for i, ax in enumerate([ax_rf, ax_qc, ax_fs, ax_u, ax0]):
    ax.spines["right"].set_visible(False)
    ax.spines["bottom"].set_visible(False)
    ax.xaxis.label.set_fontsize(15)
    ax.xaxis.set_label_coords(-0.05, 1+0.05*i)
    ax.spines['left'].set_position(('outward', 10))
    ax.spines['left'].set_bounds(0, 30)
ax_rf.set_xlim(0, 46)

ax_u.set_title("Resistivity plot CPT measurement GEO-93/023-SII-E", fontsize=12)

ax0.invert_yaxis()
ax_rf.invert_xaxis()
ax_u.set_ylabel("Depth(m)", fontsize=12)
fig.legend(loc='lower center', ncol=4)
fig.tight_layout()
```

## Visualize locations

Using Folium, we can display the results of our search on a map.

```python
# import the necessary modules (not included in the requirements of pydov!)
import folium
from folium.plugins import MarkerCluster
from pyproj import Transformer
```

```python
# convert the coordinates to lat/lon for folium
def convert_latlon(x1, y1):
    transformer = Transformer.from_crs("epsg:31370", "epsg:4326", always_xy=True)
    x2,y2 = transformer.transform(x1, y1)
    return x2, y2

df['lon'], df['lat'] = zip(*map(convert_latlon, df['x'], df['y']))
# convert to list
loclist = df[['lat', 'lon']].values.tolist()
```

```python
# initialize the Folium map on the centre of the selected locations, play with the zoom until ok
fmap = folium.Map(location=[df['lat'].mean(), df['lon'].mean()], zoom_start=11)
marker_cluster = MarkerCluster().add_to(fmap)
for loc in range(0, len(loclist)):
    folium.Marker(loclist[loc], popup=df['sondeernummer'][loc]).add_to(marker_cluster)
fmap

```

Make this Notebook Trusted to load map: File -> Trust Notebook


# Econometrics HW_08

**11510691 程远星$\DeclareMathOperator*{\argmin}{argmin}
\DeclareMathOperator*{\argmax}{argmax}
\DeclareMathOperator*{\plim}{plim}
\newcommand{\using}[1]{\stackrel{\mathrm{#1}}{=}}
\newcommand{\ffrac}{\displaystyle \frac}
\newcommand{\asim}{\overset{\text{a}}{\sim}}
\newcommand{\space}{\text{ }}
\newcommand{\bspace}{\;\;\;\;}
\newcommand{\QQQ}{\boxed{?\:}}
\newcommand{\void}{\left.\right.}
\newcommand{\Tran}[1]{{#1}^{\mathrm{T}}}
\newcommand{\d}[1]{\displaystyle{#1}}
\newcommand{\CB}[1]{\left\{ #1 \right\}}
\newcommand{\SB}[1]{\left[ #1 \right]}
\newcommand{\P}[1]{\left( #1 \right)}
\newcommand{\abs}[1]{\left| #1 \right|}
\newcommand{\norm}[1]{\left\| #1 \right\|}
\newcommand{\dd}{\mathrm{d}}
\newcommand{\Exp}{\mathrm{E}}
\newcommand{\RR}{\mathbb{R}}
\newcommand{\EE}{\mathbb{E}}
\newcommand{\NN}{\mathbb{N}}
\newcommand{\ZZ}{\mathbb{Z}}
\newcommand{\QQ}{\mathbb{Q}}
\newcommand{\AcA}{\mathscr{A}}
\newcommand{\FcF}{\mathscr{F}}
\newcommand{\Var}[2][\,\!]{\mathrm{Var}_{#1}\left[#2\right]}
\newcommand{\Avar}[2][\,\!]{\mathrm{Avar}_{#1}\left[#2\right]}
\newcommand{\Cov}[2][\,\!]{\mathrm{Cov}_{#1}\left(#2\right)}
\newcommand{\Corr}[2][\,\!]{\mathrm{Corr}_{#1}\left(#2\right)}
\newcommand{\I}[1]{\mathrm{I}\left( #1 \right)}
\newcommand{\N}[1]{\mathcal{N} \left( #1 \right)}
\newcommand{\ow}{\text{otherwise}}
\void^\dagger$**

## Question 5

$\P{1}$

$\bspace$The two set of standard errors are so close and there's really no needs to distinguish them from each other.

$\P{2}$

$\bspace$Holding all other variables fixed, the probability of smoking changes by about $-0.029\times4=-0.116$.

$\P{3}$

$$\abs{\ffrac{0.02} {2\times 0.00026}}\approx 38.46153846153846$$

$\P{4}$

$\bspace$Holding other factors in the equation fixed, the probability to smoke will decrease $0.101$ for a person in a state with restaurant smoking restrictions.

$\P{5}$

$$\begin{align}\widehat{\text{smoke}} &= 0.656-0.069\times\log\P{67.44} + 0.012\times\log\P{6500} - 0.029 \times 16\\
&\bspace+ 0.0207\times77 -0.00026\times77^2 -0.101\times0-0.026\times 0\\
&\approx 0.0052
\end{align}$$

## Question 6

$\P{1}$

$\bspace$The numerator has $k+1$ regressors, and that's the $df$ for it. For the denominator, its $df$ is $n-\P{k-2}$

$\P{2}$

$\bspace$In BP test, there's one more regressor thus it's got a higher $R$-squared. In White test, the model has more restrictions and thus the $R$-squared will be higher.

$\P{3}$

$\bspace$For $t$ test statistic will be a little bit smaller however the change of $F$ statistic is unpredictable. The $\text{SSR}$s will be larger while $df$s also do.

$\P{4}$

$\bspace$Collinearity. Since the estimated equation will be a linear combination of all variables.

## Question 7

$\P{1}$

$\bspace$Since the two are uncorrelated, we have $\Var{u_{i,e}} = \Var{f_i} + \Var{v_{i,e}} = \sigma_f^2 + \sigma_v^2$

$\P{2}$

$$\begin{align}
\Cov{u_{i,e},u_{i,g}} &= \Cov{f_i + v_{i,e},f_i + v_{i,g}}\\
&= \Cov{f_i,f_i} + \Cov{f_i,v_{i,g}} + \Cov{v_{i,e},f_i} + \Cov{v_{i,e},v_{i,g}}\\
&= \Cov{f_i,f_i} + 0 + 0 + 0 = \Var{f_i}
\end{align}$$

$\P{3}$

$$\begin{align}
\Var{\bar u_i} &= \Var{\ffrac{1} {m_i}\sum_{e=1}^{m_i} u_{i,e}} \\
&= \Var{f_i + \ffrac{1} {m_i}\sum_{e=1}^{m_i} v_{i,e}}\\
&= \Var{f_i} + \Var{\ffrac{1} {m_i}\sum_{e=1}^{m_i} v_{i,e}}\\
&= \sigma_f^2 + \ffrac{\sigma_v^2} {m_i}
\end{align}$$

$\P{4}$

$\bspace$From the weighted OLS method, our target is to find some specific weight so that $\Var{\bar u_i} = \ffrac{\sigma_f^2} {m_i}$. If we take the weight so that the data are simply averaged, then like the preceding problem, we failed.