Resumiendo mediciones#
De una base de datos accesible por SQL que contiene información sobre experimentos, imágenes adquiridas durante los experimentos y mediciones correspondientes, nos gustaría extraer estadísticas resumidas.
import pandas as pd
from pandasql import sqldf
experiment = pd.read_csv("../../data/experiments.csv")
image = pd.read_csv("../../data/images.csv")
overview = pd.read_csv("../../data/overview.csv")
query_database = lambda q: sqldf(q, globals())
Datos de ejemplo#
Solo como recordatorio, nuestra tabla de visión general contiene la información clave recuperada de nuestra base de datos sobre el número de células contadas en imágenes que fueron adquiridas durante experimentos.
query = """
SELECT *
FROM overview
"""
query_database(query)
| Unnamed: 0 | experiment_name | Filename | time_after_exposure_in_s | number_of_cells | |
|---|---|---|---|---|---|
| 0 | 0 | High dose | image0.tif | 0 | 96 |
| 1 | 1 | High dose | image0.tif | 1 | 47 |
| 2 | 2 | High dose | image0.tif | 2 | 32 |
| 3 | 3 | High dose | image0.tif | 3 | 24 |
| 4 | 4 | High dose | image0.tif | 4 | 19 |
| ... | ... | ... | ... | ... | ... |
| 95 | 95 | Control | image9.tif | 5 | 142 |
| 96 | 96 | Control | image9.tif | 6 | 148 |
| 97 | 97 | Control | image9.tif | 7 | 144 |
| 98 | 98 | Control | image9.tif | 8 | 141 |
| 99 | 99 | Control | image9.tif | 9 | 140 |
100 rows × 5 columns
Agrupando filas#
La declaración GROUP BY permite agrupar tablas largas en otras más cortas y nos permite hacer estadísticas descriptivas. Por ejemplo, podemos determinar el número más pequeño y más grande de células observadas durante un experimento usando los llamados agregadores MIN() y MAX().
query = """
SELECT experiment_name, MIN(number_of_cells), MAX(number_of_cells)
FROM overview
GROUP BY experiment_name
"""
query_database(query)
| experiment_name | MIN(number_of_cells) | MAX(number_of_cells) | |
|---|---|---|---|
| 0 | Control | 113 | 159 |
| 1 | High dose | 9 | 151 |
| 2 | Medium dose | 7 | 158 |
Los grupos también pueden formarse utilizando múltiples columnas. Aquí también vemos que es común especificar las columnas utilizadas para agrupar dos veces, una vez después de GROUP BY y otra vez después de SELECT porque queremos ver la agrupación en la tabla.
query = """
SELECT experiment_name, Filename, MIN(number_of_cells), MAX(number_of_cells)
FROM overview
GROUP BY experiment_name, Filename
"""
query_database(query)
| experiment_name | Filename | MIN(number_of_cells) | MAX(number_of_cells) | |
|---|---|---|---|---|
| 0 | Control | image6.tif | 147 | 156 |
| 1 | Control | image7.tif | 113 | 122 |
| 2 | Control | image8.tif | 145 | 159 |
| 3 | Control | image9.tif | 140 | 149 |
| 4 | High dose | image0.tif | 9 | 96 |
| 5 | High dose | image1.tif | 15 | 151 |
| 6 | High dose | image2.tif | 9 | 97 |
| 7 | Medium dose | image3.tif | 15 | 158 |
| 8 | Medium dose | image4.tif | 7 | 76 |
| 9 | Medium dose | image5.tif | 14 | 147 |
Una estrategia similar utiliza el agregador COUNT para contar el número de imágenes adquiridas por experimento.
query = """
SELECT experiment_name, COUNT(Filename)
FROM overview
GROUP BY experiment_name
"""
query_database(query)
| experiment_name | COUNT(Filename) | |
|---|---|---|
| 0 | Control | 40 |
| 1 | High dose | 30 |
| 2 | Medium dose | 30 |
Combinando estadísticas#
Supongamos que las mediciones en nuestra base de datos resultan de un análisis de lapso de tiempo. Una mirada rápida a un solo archivo de imagen y las mediciones correspondientes muestra que el número de células está disminuyendo con el tiempo.
query = """
SELECT *
FROM overview
WHERE Filename = "image0.tif"
"""
query_database(query)
| Unnamed: 0 | experiment_name | Filename | time_after_exposure_in_s | number_of_cells | |
|---|---|---|---|---|---|
| 0 | 0 | High dose | image0.tif | 0 | 96 |
| 1 | 1 | High dose | image0.tif | 1 | 47 |
| 2 | 2 | High dose | image0.tif | 2 | 32 |
| 3 | 3 | High dose | image0.tif | 3 | 24 |
| 4 | 4 | High dose | image0.tif | 4 | 19 |
| 5 | 5 | High dose | image0.tif | 5 | 16 |
| 6 | 6 | High dose | image0.tif | 6 | 13 |
| 7 | 7 | High dose | image0.tif | 7 | 11 |
| 8 | 8 | High dose | image0.tif | 8 | 10 |
| 9 | 9 | High dose | image0.tif | 9 | 9 |
Ahora podemos determinar el número promedio de células al comienzo del experimento promediando los primeros 3 puntos de tiempo.
query = """
SELECT Filename, AVG(number_of_cells) as number_of_cells
FROM overview
WHERE time_after_exposure_in_s < 3
GROUP BY Filename
"""
query_database(query)
| Filename | number_of_cells | |
|---|---|---|
| 0 | image0.tif | 58.333333 |
| 1 | image1.tif | 93.000000 |
| 2 | image2.tif | 58.000000 |
| 3 | image3.tif | 97.333333 |
| 4 | image4.tif | 46.333333 |
| 5 | image5.tif | 89.666667 |
| 6 | image6.tif | 150.666667 |
| 7 | image7.tif | 113.666667 |
| 8 | image8.tif | 151.000000 |
| 9 | image9.tif | 147.666667 |
query = """
SELECT Filename, AVG(number_of_cells) as number_of_cells
FROM overview
WHERE time_after_exposure_in_s < 3
GROUP BY Filename
"""
cell_count_early = query_database(query)
query = """
SELECT Filename, AVG(number_of_cells) as number_of_cells
FROM overview
WHERE time_after_exposure_in_s > 6
GROUP BY Filename;
"""
cell_count_late = query_database(query)
query = """
SELECT cell_count_early.Filename, (cell_count_late.number_of_cells / cell_count_early.number_of_cells) AS cell_count_ratio
FROM cell_count_early
INNER JOIN cell_count_late ON cell_count_early.Filename = cell_count_late.Filename
"""
cell_count_ratio_overview = query_database(query)
cell_count_ratio_overview
| Filename | cell_count_ratio | |
|---|---|---|
| 0 | image0.tif | 0.171429 |
| 1 | image1.tif | 0.182796 |
| 2 | image2.tif | 0.172414 |
| 3 | image3.tif | 0.171233 |
| 4 | image4.tif | 0.172662 |
| 5 | image5.tif | 0.174721 |
| 6 | image6.tif | 0.986726 |
| 7 | image7.tif | 1.055718 |
| 8 | image8.tif | 0.991170 |
| 9 | image9.tif | 0.959368 |
Ahora sabemos la fracción de células que sobrevivieron en qué archivo. Necesitamos usar la declaración JOIN nuevamente para saber en qué experimento se observaron estas proporciones de supervivencia.
query = """
SELECT experiment.Comment, cell_count_ratio_overview.cell_count_ratio
FROM cell_count_ratio_overview
INNER JOIN image ON cell_count_ratio_overview.Filename = image.Filename
INNER JOIN experiment ON image.experiment_ID = experiment.ID
"""
query_database(query)
| Comment | cell_count_ratio | |
|---|---|---|
| 0 | High dose | 0.171429 |
| 1 | High dose | 0.182796 |
| 2 | High dose | 0.172414 |
| 3 | Medium dose | 0.171233 |
| 4 | Medium dose | 0.172662 |
| 5 | Medium dose | 0.174721 |
| 6 | Control | 0.986726 |
| 7 | Control | 1.055718 |
| 8 | Control | 0.991170 |
| 9 | Control | 0.959368 |
También estos pueden resumirse utilizando la declaración GROUP BY. Los buenos científicos no solo informan el promedio de estas mediciones, sino también el número de imágenes que se han analizado.
query = """
SELECT
experiment.Comment as experiment_name,
AVG(cell_count_ratio_overview.cell_count_ratio) as mean_cell_count_ratio,
COUNT(cell_count_ratio_overview.cell_count_ratio) as num_images
FROM cell_count_ratio_overview
INNER JOIN image ON cell_count_ratio_overview.Filename = image.Filename
INNER JOIN experiment ON image.experiment_ID = experiment.ID
GROUP BY experiment.Comment
"""
query_database(query)
| experiment_name | mean_cell_count_ratio | num_images | |
|---|---|---|---|
| 0 | Control | 0.998246 | 4 |
| 1 | High dose | 0.175546 | 3 |
| 2 | Medium dose | 0.172872 | 3 |
Ejercicio#
Determinar el recuento promedio de células durante todo el lapso de tiempo para todas las imágenes individualmente.
Resumir estas mediciones para imágenes individuales para presentar el promedio de cada experimento.