Descripción del proyecto y justificación:¶
La metagenómica es una herramienta que permite conocer la diversidad de microorganismos y sus funciones, sin la necesidad de cultivarlos, considerando que solo un porcentaje muy pequeño se puede cultivar en un laboratorio. Esto permite analizar el microbioma de muestras ambientales, como el suelo. Los suelos se han investigado siempre en función de sus características físicas y químicas; pero, hasta hace algunos años se han reportado estudios que involucran la comprensión de la dinámica de los microorganismos del suelo. Realizar estudios metagenómicos de una muestra ambiental involucra analizar gran cantidad de secuencias de material genético, por lo que se necesita implementar métodos para lograr sacar el mayor provecho a esa información, por ejemplo, por medio de bibliotecas de Python. Este proyecto consiste en descargar un dataset con información de microbioma de suelos de Finlandia, para filtrar la información más importante, analizarla y comparar los datos con resultados obtenidos en un proyecto de investigación propia.
Antecedentes:¶
El análisis de las características, taxonomía y ecología de los microorganismos en muestras ambientales, se ha logrado de manera más eficiente mediante los avances en la secuenciación y la bioinformática. Estos conocimientos pueden ser una herramienta para brindar puntuaciones de calidad del suelo, como se muestra en los resultados obtenidos por Hermans et al. (2020), en donde se analizaron 3000 muestras de suelo de 606 sitios de Nueva Zelanda. Además, en este tipo de investigaciones, no solo es importante la información obtenida a partir de las secuencias del material genético, por el contrario, se vuelve más informativa en conjunto con metadatos, que incluyan descripciones, características y otros tipos de procesamientos de muestras, por ejemplo, datos de análisis fisicoquímicos, condiciones ambientales, tipo de muestra, tratamientos, entre otros. Un estudio realizado en diferentes tipos de usos de suelos de países europeos, determinó diferencias significativas en las estructuras de la comunidad de bacterias y que es explicado en gran parte por las propiedades del suelo en relación con su pH, contenido total de carbón y textura (Plassart et al., 2019). La ciencia de datos permite filtrar y limpiar las secuencias de ADN, transformar esa información mediante bases de datos, analizar, visualizar los datos y aplicar estadísticas. Algunos de los métodos utilizados por Berihu et al. (2023), en función de seleccionar taxones beneficiosos del suelo para los cultivos, fueron filtrar los datos de la secuenciación, eliminando secuencias de baja calidad. Después, se utilizó una base de datos de proteínas de NCBI (National Center for Biotechnology Information) para asignar anotaciones de funciones. Con estos datos se desarrolló un método de simulación de las actividades metabólicas. Además, se aplicó estadística y se visualizaron los datos mediante gráficos de análisis de coordenadas principales. Los aportes a la información generada sobre el microbioma del suelo, como se mencionó anteriormente, puede ser por medio de análisis de un conjunto de muestras de un estudio en específico, pero también puede estar enfocado en crear bases de datos a partir de otras bases de datos, para de esta manera tener referencias específicas del suelo. Edwin et al. (2024), unieron información de bases de datos de NCBI y de RefSoil, para simular una comunidad, mediante genomas que son comunes en ecosistemas del suelo.
Descipción del problema:¶
¿Es posible filtrar la información del dataset "Soil metagenome from healthy and unhealthy agricultural soil" para analizar, comparar y visualizar los datos más relevantes?
Objetivo:¶
Analizar el dataset "Soil metagenome from healthy and unhealthy agricultural soil", mediante bibliotecas de aprendizaje automático, para la visualización de los taxones más relevantes y la comparación con otro estudio de metagenómica de suelos.
Descipción del conjunto de datos:¶
El dataset "Soil metagenome from healthy and unhealthy agricultural soil" (MGnify, 2020), es un conjunto de datos sobre microbioma de suelos agrícolas de Finlandia, considerados saludables y no saludables, publicado en GBIF (Global Biodiversity Information Facility) el 04 de febrero del 2020 por la Universidad de Helsinki.
El mapa de Finlandia fue descargado en: gadm.org
La información de los grupos taxonómicos para realizar la comparación corresponden a los resultados de una investigación (mi tesis en desarrollo) sobre bacterias de suelos de cafetales de Naranjo, que son considerados de calidad Baja y Media para el cultivo del café, según la zonificación agroecológica del Instituto Nacional de Tecnología Agropecuaria (INTA, 2019). Mediante los análisis de la secuenciación de ADN de muestras de suelos, estos grupos taxonómicos son considerados bioindicadores de la calidad Baja y Media (p<0.05).
Código¶
!pip install pandas
!pip install ydata-profiling
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from ydata_profiling import ProfileReport
!pip install geodatasets
import geopandas as gpd
import geodatasets
Requirement already satisfied: pandas in /usr/local/lib/python3.10/dist-packages (2.0.3) Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.10/dist-packages (from pandas) (2.8.2) Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas) (2023.4) Requirement already satisfied: tzdata>=2022.1 in /usr/local/lib/python3.10/dist-packages (from pandas) (2024.1) Requirement already satisfied: numpy>=1.21.0 in /usr/local/lib/python3.10/dist-packages (from pandas) (1.25.2) Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.8.2->pandas) (1.16.0) Collecting ydata-profiling Downloading ydata_profiling-4.8.3-py2.py3-none-any.whl (359 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 359.5/359.5 kB 2.9 MB/s eta 0:00:00 Requirement already satisfied: scipy<1.14,>=1.4.1 in /usr/local/lib/python3.10/dist-packages (from ydata-profiling) (1.11.4) Requirement already satisfied: pandas!=1.4.0,<3,>1.1 in /usr/local/lib/python3.10/dist-packages (from ydata-profiling) (2.0.3) Requirement already satisfied: matplotlib<3.9,>=3.2 in /usr/local/lib/python3.10/dist-packages (from ydata-profiling) (3.7.1) Requirement already satisfied: pydantic>=2 in /usr/local/lib/python3.10/dist-packages (from ydata-profiling) (2.7.2) Requirement already satisfied: PyYAML<6.1,>=5.0.0 in /usr/local/lib/python3.10/dist-packages (from ydata-profiling) (6.0.1) Requirement already satisfied: jinja2<3.2,>=2.11.1 in /usr/local/lib/python3.10/dist-packages (from ydata-profiling) (3.1.4) Collecting visions[type_image_path]<0.7.7,>=0.7.5 (from ydata-profiling) Downloading visions-0.7.6-py3-none-any.whl (104 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 104.8/104.8 kB 8.6 MB/s eta 0:00:00 Requirement already satisfied: numpy<2,>=1.16.0 in /usr/local/lib/python3.10/dist-packages (from ydata-profiling) (1.25.2) Collecting htmlmin==0.1.12 (from ydata-profiling) Downloading htmlmin-0.1.12.tar.gz (19 kB) Preparing metadata (setup.py) ... done Collecting phik<0.13,>=0.11.1 (from ydata-profiling) Downloading phik-0.12.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (686 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 686.1/686.1 kB 35.4 MB/s eta 0:00:00 Requirement already satisfied: requests<3,>=2.24.0 in /usr/local/lib/python3.10/dist-packages (from ydata-profiling) (2.31.0) Requirement already satisfied: tqdm<5,>=4.48.2 in /usr/local/lib/python3.10/dist-packages (from ydata-profiling) (4.66.4) Requirement already satisfied: seaborn<0.14,>=0.10.1 in /usr/local/lib/python3.10/dist-packages (from ydata-profiling) (0.13.1) Collecting multimethod<2,>=1.4 (from ydata-profiling) Downloading multimethod-1.11.2-py3-none-any.whl (10 kB) Requirement already satisfied: statsmodels<1,>=0.13.2 in /usr/local/lib/python3.10/dist-packages (from ydata-profiling) (0.14.2) Collecting typeguard<5,>=3 (from ydata-profiling) Downloading typeguard-4.3.0-py3-none-any.whl (35 kB) Collecting imagehash==4.3.1 (from ydata-profiling) Downloading ImageHash-4.3.1-py2.py3-none-any.whl (296 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 296.5/296.5 kB 26.7 MB/s eta 0:00:00 Requirement already satisfied: wordcloud>=1.9.1 in /usr/local/lib/python3.10/dist-packages (from ydata-profiling) (1.9.3) Collecting dacite>=1.8 (from ydata-profiling) Downloading dacite-1.8.1-py3-none-any.whl (14 kB) Requirement already satisfied: numba<1,>=0.56.0 in /usr/local/lib/python3.10/dist-packages (from ydata-profiling) (0.58.1) Requirement already satisfied: PyWavelets in /usr/local/lib/python3.10/dist-packages (from imagehash==4.3.1->ydata-profiling) (1.6.0) Requirement already satisfied: pillow in /usr/local/lib/python3.10/dist-packages (from imagehash==4.3.1->ydata-profiling) (9.4.0) Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2<3.2,>=2.11.1->ydata-profiling) (2.1.5) Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<3.9,>=3.2->ydata-profiling) (1.2.1) Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib<3.9,>=3.2->ydata-profiling) (0.12.1) Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib<3.9,>=3.2->ydata-profiling) (4.52.4) Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<3.9,>=3.2->ydata-profiling) (1.4.5) Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib<3.9,>=3.2->ydata-profiling) (24.0) Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<3.9,>=3.2->ydata-profiling) (3.1.2) Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib<3.9,>=3.2->ydata-profiling) (2.8.2) Requirement already satisfied: llvmlite<0.42,>=0.41.0dev0 in /usr/local/lib/python3.10/dist-packages (from numba<1,>=0.56.0->ydata-profiling) (0.41.1) Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas!=1.4.0,<3,>1.1->ydata-profiling) (2023.4) Requirement already satisfied: tzdata>=2022.1 in /usr/local/lib/python3.10/dist-packages (from pandas!=1.4.0,<3,>1.1->ydata-profiling) (2024.1) Requirement already satisfied: joblib>=0.14.1 in /usr/local/lib/python3.10/dist-packages (from phik<0.13,>=0.11.1->ydata-profiling) (1.4.2) Requirement already satisfied: annotated-types>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from pydantic>=2->ydata-profiling) (0.7.0) Requirement already satisfied: pydantic-core==2.18.3 in /usr/local/lib/python3.10/dist-packages (from pydantic>=2->ydata-profiling) (2.18.3) Requirement already satisfied: typing-extensions>=4.6.1 in /usr/local/lib/python3.10/dist-packages (from pydantic>=2->ydata-profiling) (4.12.0) Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2.24.0->ydata-profiling) (3.3.2) Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2.24.0->ydata-profiling) (3.7) Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2.24.0->ydata-profiling) (2.0.7) Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2.24.0->ydata-profiling) (2024.2.2) Requirement already satisfied: patsy>=0.5.6 in /usr/local/lib/python3.10/dist-packages (from statsmodels<1,>=0.13.2->ydata-profiling) (0.5.6) Requirement already satisfied: attrs>=19.3.0 in /usr/local/lib/python3.10/dist-packages (from visions[type_image_path]<0.7.7,>=0.7.5->ydata-profiling) (23.2.0) Requirement already satisfied: networkx>=2.4 in /usr/local/lib/python3.10/dist-packages (from visions[type_image_path]<0.7.7,>=0.7.5->ydata-profiling) (3.3) Requirement already satisfied: six in /usr/local/lib/python3.10/dist-packages (from patsy>=0.5.6->statsmodels<1,>=0.13.2->ydata-profiling) (1.16.0) Building wheels for collected packages: htmlmin Building wheel for htmlmin (setup.py) ... done Created wheel for htmlmin: filename=htmlmin-0.1.12-py3-none-any.whl size=27080 sha256=cd49fc6872afe215b0bdbdfe1324dcda01871ab78472d8f77cdd995274eb6c56 Stored in directory: /root/.cache/pip/wheels/dd/91/29/a79cecb328d01739e64017b6fb9a1ab9d8cb1853098ec5966d Successfully built htmlmin Installing collected packages: htmlmin, typeguard, multimethod, dacite, imagehash, visions, phik, ydata-profiling Successfully installed dacite-1.8.1 htmlmin-0.1.12 imagehash-4.3.1 multimethod-1.11.2 phik-0.12.4 typeguard-4.3.0 visions-0.7.6 ydata-profiling-4.8.3 Collecting geodatasets Downloading geodatasets-2023.12.0-py3-none-any.whl (19 kB) Requirement already satisfied: pooch in /usr/local/lib/python3.10/dist-packages (from geodatasets) (1.8.1) Requirement already satisfied: platformdirs>=2.5.0 in /usr/local/lib/python3.10/dist-packages (from pooch->geodatasets) (4.2.2) Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from pooch->geodatasets) (24.0) Requirement already satisfied: requests>=2.19.0 in /usr/local/lib/python3.10/dist-packages (from pooch->geodatasets) (2.31.0) Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->pooch->geodatasets) (3.3.2) Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->pooch->geodatasets) (3.7) Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->pooch->geodatasets) (2.0.7) Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->pooch->geodatasets) (2024.2.2) Installing collected packages: geodatasets Successfully installed geodatasets-2023.12.0
from google.colab import drive
drive.mount('/content/drive')
df = pd.read_csv('/content/drive/MyDrive/soil_metagenome.csv', delimiter='\t') # delimiter='\t' para sets separados por tabulaciones
Mounted at /content/drive
# Sumar valores faltantes
df.isna().sum()
gbifID 0 datasetKey 0 occurrenceID 0 kingdom 0 phylum 1835 class 3300 order 4953 family 8101 genus 13247 species 22109 infraspecificEpithet 25560 taxonRank 0 scientificName 0 verbatimScientificName 0 verbatimScientificNameAuthorship 25560 countryCode 0 locality 25560 stateProvince 25560 occurrenceStatus 0 individualCount 25560 publishingOrgKey 0 decimalLatitude 0 decimalLongitude 0 coordinateUncertaintyInMeters 25560 coordinatePrecision 25560 elevation 25560 elevationAccuracy 25560 depth 25560 depthAccuracy 25560 eventDate 0 day 0 month 0 year 0 taxonKey 0 speciesKey 22109 basisOfRecord 0 institutionCode 25560 collectionCode 25560 catalogNumber 25560 recordNumber 25560 identifiedBy 25560 dateIdentified 25560 license 0 rightsHolder 25560 recordedBy 25560 typeStatus 25560 establishmentMeans 25560 lastInterpreted 0 mediaType 25560 issue 0 dtype: int64
# Determinar la forma
df.shape
(25560, 50)
Filtración
#----- Primer filtro -----
# Eliminar las columnas que todos sus valores sean NaN (25560)
print("Antes:", df.columns, "\n")
df = df.dropna(axis=1, how='all')
print("Después:", df.columns)
Antes: Index(['gbifID', 'datasetKey', 'occurrenceID', 'kingdom', 'phylum', 'class', 'order', 'family', 'genus', 'species', 'infraspecificEpithet', 'taxonRank', 'scientificName', 'verbatimScientificName', 'verbatimScientificNameAuthorship', 'countryCode', 'locality', 'stateProvince', 'occurrenceStatus', 'individualCount', 'publishingOrgKey', 'decimalLatitude', 'decimalLongitude', 'coordinateUncertaintyInMeters', 'coordinatePrecision', 'elevation', 'elevationAccuracy', 'depth', 'depthAccuracy', 'eventDate', 'day', 'month', 'year', 'taxonKey', 'speciesKey', 'basisOfRecord', 'institutionCode', 'collectionCode', 'catalogNumber', 'recordNumber', 'identifiedBy', 'dateIdentified', 'license', 'rightsHolder', 'recordedBy', 'typeStatus', 'establishmentMeans', 'lastInterpreted', 'mediaType', 'issue'], dtype='object') Después: Index(['gbifID', 'datasetKey', 'occurrenceID', 'kingdom', 'phylum', 'class', 'order', 'family', 'genus', 'species', 'taxonRank', 'scientificName', 'verbatimScientificName', 'countryCode', 'occurrenceStatus', 'publishingOrgKey', 'decimalLatitude', 'decimalLongitude', 'eventDate', 'day', 'month', 'year', 'taxonKey', 'speciesKey', 'basisOfRecord', 'license', 'lastInterpreted', 'issue'], dtype='object')
# Creamos el informe
nombre = "Soil microbiome"
profile = ProfileReport(df, title=nombre, explorative=True)
# Mostrar el informe en un notebook
profile.to_notebook_iframe()
Output hidden; open in https://colab.research.google.com to view.
# Descargar el .htlm en la sección de carpetas
profile.to_file("Reporte.htlm")
/usr/local/lib/python3.10/dist-packages/ydata_profiling/profile_report.py:363: UserWarning: Try running command: 'pip install --upgrade Pillow' to avoid ValueError warnings.warn( /usr/local/lib/python3.10/dist-packages/ydata_profiling/profile_report.py:384: UserWarning: Extension .htlm not supported. For now we assume .html was intended. To remove this warning, please use .html or .json. warnings.warn(
Export report to file: 0%| | 0/1 [00:00<?, ?it/s]
#----- Segundo filtro -----
# Filtrar las columnas con información importante y diferente
print("Antes:", df.columns, "\n")
df = df[['gbifID', 'datasetKey', 'occurrenceID', 'kingdom', 'phylum', 'class',
'order', 'family', 'genus', 'species', 'taxonRank', 'scientificName',
'countryCode', 'decimalLatitude', 'decimalLongitude',
'eventDate', 'taxonKey', 'speciesKey', 'issue']]
print("Después:", df.columns)
Antes: Index(['gbifID', 'datasetKey', 'occurrenceID', 'kingdom', 'phylum', 'class', 'order', 'family', 'genus', 'species', 'taxonRank', 'scientificName', 'verbatimScientificName', 'countryCode', 'occurrenceStatus', 'publishingOrgKey', 'decimalLatitude', 'decimalLongitude', 'eventDate', 'day', 'month', 'year', 'taxonKey', 'speciesKey', 'basisOfRecord', 'license', 'lastInterpreted', 'issue'], dtype='object') Después: Index(['gbifID', 'datasetKey', 'occurrenceID', 'kingdom', 'phylum', 'class', 'order', 'family', 'genus', 'species', 'taxonRank', 'scientificName', 'countryCode', 'decimalLatitude', 'decimalLongitude', 'eventDate', 'taxonKey', 'speciesKey', 'issue'], dtype='object')
df.head(3)
gbifID | datasetKey | occurrenceID | kingdom | phylum | class | order | family | genus | species | ... | identifiedBy | dateIdentified | license | rightsHolder | recordedBy | typeStatus | establishmentMeans | lastInterpreted | mediaType | issue | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 3916717560 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198885_Bacteria::Verrucomicrobia:Opituta... | Bacteria | Verrucomicrobiota | Verrucomicrobiae | Opitutales | Opitutaceae | Opitutus | NaN | ... | NaN | NaN | CC_BY_4_0 | NaN | NaN | NaN | NaN | 2024-05-18T16:56:01.993Z | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... |
1 | 3916717559 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198894_Bacteria::Proteobacteria:Zetaprot... | Bacteria | Proteobacteria | Zetaproteobacteria | Mariprofundales | Mariprofundaceae | Mariprofundus | NaN | ... | NaN | NaN | CC_BY_4_0 | NaN | NaN | NaN | NaN | 2024-05-18T16:56:01.993Z | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... |
2 | 3916717558 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198886_Bacteria::Actinobacteria:Actinoba... | Bacteria | Actinobacteriota | Actinomycetia | Actinomycetales | Microbacteriaceae | Leifsonia | NaN | ... | NaN | NaN | CC_BY_4_0 | NaN | NaN | NaN | NaN | 2024-05-18T16:56:05.146Z | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... |
3 rows × 50 columns
Categorización
# Crear una función para categorizar según el lugar de muestreo
def categorizar(fila):
ID = fila["decimalLatitude"]
if ID == 60.746:
return "tipo_1"
elif ID == 60.559:
return "tipo_2"
elif ID == 60.561:
return "tipo_2"
else:
return "tipo_3"
# Aplicar la función a cada fila y agregar una nueva columna
df["Categoría"] = df.apply(categorizar, axis=1)
df
gbifID | datasetKey | occurrenceID | kingdom | phylum | class | order | family | genus | species | taxonRank | scientificName | countryCode | decimalLatitude | decimalLongitude | eventDate | taxonKey | speciesKey | issue | Categoría | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 3916717560 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198885_Bacteria::Verrucomicrobia:Opituta... | Bacteria | Verrucomicrobiota | Verrucomicrobiae | Opitutales | Opitutaceae | Opitutus | NaN | GENUS | Opitutus Chin et al., 2001 | FI | 60.746 | 21.689 | 2016-07-25 | 3229020 | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_1 |
1 | 3916717559 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198894_Bacteria::Proteobacteria:Zetaprot... | Bacteria | Proteobacteria | Zetaproteobacteria | Mariprofundales | Mariprofundaceae | Mariprofundus | NaN | GENUS | Mariprofundus Emerson et al., 2010 | FI | 60.425 | 23.000 | 2016-07-25 | 5905993 | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_3 |
2 | 3916717558 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198886_Bacteria::Actinobacteria:Actinoba... | Bacteria | Actinobacteriota | Actinomycetia | Actinomycetales | Microbacteriaceae | Leifsonia | NaN | GENUS | Leifsonia Evtushenko et al., 2000 | FI | 60.425 | 23.000 | 2016-07-25 | 8159185 | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_3 |
3 | 3916717557 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198897_Bacteria::Actinobacteria:Nitrilir... | Bacteria | Actinobacteriota | Actinomycetia | NaN | NaN | NaN | NaN | CLASS | Nitriliruptoria | FI | 60.426 | 22.992 | 2016-07-25 | 10900290 | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_3 |
4 | 3916717556 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198890_Bacteria::Actinobacteria:Actinoba... | Bacteria | Actinobacteriota | Actinomycetia | Mycobacteriales | Pseudonocardiaceae | Allokutzneria | Allokutzneria albata | SPECIES | Allokutzneria albata (Tomita et al., 1993) Lab... | FI | 60.559 | 22.640 | 2016-07-25 | 8374936 | 8374936.0 | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_2 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
25555 | 2441745103 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198881_Bacteria::Acidobacteria:Solibacte... | Bacteria | Acidobacteriota | NaN | NaN | NaN | NaN | NaN | PHYLUM | Acidobacteria | FI | 60.746 | 21.689 | 2016-07-25 | 25 | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_1 |
25556 | 2441745092 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198881_Bacteria::Planctomycetes:Planctom... | Bacteria | Planctomycetota | Planctomycetia | Planctomycetales | NaN | NaN | NaN | ORDER | Planctomycetales | FI | 60.746 | 21.689 | 2016-07-25 | 1218 | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_1 |
25557 | 2441744962 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198881_Bacteria::Actinobacteria:::::Acti... | Bacteria | Actinobacteriota | NaN | NaN | NaN | NaN | NaN | PHYLUM | Actinobacteriota | FI | 60.746 | 21.689 | 2016-07-25 | 10813635 | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_1 |
25558 | 2441744626 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198881_Bacteria:::::::bacterium_enrichme... | Bacteria | NaN | NaN | NaN | NaN | NaN | NaN | KINGDOM | Bacteria | FI | 60.746 | 21.689 | 2016-07-25 | 3 | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_1 |
25559 | 2441744624 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198881_Bacteria::Acidobacteria:Blastocat... | Bacteria | Acidobacteriota | Blastocatellia | Pyrinomonadales | Blastocatellaceae | Aridibacter | NaN | GENUS | Aridibacter Huber et al., 2014 | FI | 60.746 | 21.689 | 2016-07-25 | 8427336 | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_1 |
25560 rows × 20 columns
Mapas
# Cargar el mapa de Finlandia
fi_mapa = gpd.read_file('gadm41_FIN_2.shp')
fi_mapa
geometry | |
---|---|
0 | POLYGON ((29.62012 61.93353, 29.62154 61.93797... |
1 | POLYGON ((28.05437 62.28169, 28.04478 62.28224... |
2 | POLYGON ((26.13442 61.15151, 26.12514 61.15193... |
3 | POLYGON ((26.50956 61.29203, 26.50025 61.29247... |
4 | MULTIPOLYGON (((24.19583 65.60833, 24.19792 65... |
5 | POLYGON ((29.12566 63.84394, 29.11557 63.84456... |
6 | MULTIPOLYGON (((25.24760 63.60816, 25.23753 63... |
7 | MULTIPOLYGON (((25.22448 60.12656, 25.22448 60... |
8 | MULTIPOLYGON (((27.39792 60.30417, 27.39636 60... |
9 | POLYGON ((26.21460 60.75100, 26.21373 60.74652... |
10 | POLYGON ((27.98806 60.66637, 27.97896 60.66691... |
11 | MULTIPOLYGON (((22.96194 59.75264, 22.96194 59... |
12 | POLYGON ((26.30343 61.62195, 26.30360 61.62281... |
13 | MULTIPOLYGON (((24.17770 63.14720, 24.16798 63... |
14 | MULTIPOLYGON (((22.07083 59.73736, 22.07139 59... |
15 | MULTIPOLYGON (((21.29427 61.97760, 21.29427 61... |
16 | POLYGON ((25.40037 60.84913, 25.39961 60.84466... |
17 | MULTIPOLYGON (((23.77942 61.05702, 23.77888 61... |
18 | MULTIPOLYGON (((21.41042 61.06250, 21.40833 61... |
19 | POLYGON ((21.63754 62.02965, 21.63746 62.02965... |
20 | POLYGON ((24.59601 60.65826, 24.59537 60.65378... |
# Generar el mapa por regiones
fi_mapa.plot(figsize = (8,8), edgecolor="black")
<Axes: >
# Convertir las coordenadas
obvs_points = gpd.points_from_xy(df.decimalLongitude, df.decimalLatitude)
#Crear un geodataframe en base a un dataframe
obvs_gdf = gpd.GeoDataFrame(df, geometry=obvs_points)
obvs_gdf.head()
gbifID | datasetKey | occurrenceID | kingdom | phylum | class | order | family | genus | species | ... | scientificName | countryCode | decimalLatitude | decimalLongitude | eventDate | taxonKey | speciesKey | issue | Categoría | geometry | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 3916717560 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198885_Bacteria::Verrucomicrobia:Opituta... | Bacteria | Verrucomicrobiota | Verrucomicrobiae | Opitutales | Opitutaceae | Opitutus | NaN | ... | Opitutus Chin et al., 2001 | FI | 60.746 | 21.689 | 2016-07-25 | 3229020 | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_1 | POINT (21.68900 60.74600) |
1 | 3916717559 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198894_Bacteria::Proteobacteria:Zetaprot... | Bacteria | Proteobacteria | Zetaproteobacteria | Mariprofundales | Mariprofundaceae | Mariprofundus | NaN | ... | Mariprofundus Emerson et al., 2010 | FI | 60.425 | 23.000 | 2016-07-25 | 5905993 | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_3 | POINT (23.00000 60.42500) |
2 | 3916717558 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198886_Bacteria::Actinobacteria:Actinoba... | Bacteria | Actinobacteriota | Actinomycetia | Actinomycetales | Microbacteriaceae | Leifsonia | NaN | ... | Leifsonia Evtushenko et al., 2000 | FI | 60.425 | 23.000 | 2016-07-25 | 8159185 | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_3 | POINT (23.00000 60.42500) |
3 | 3916717557 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198897_Bacteria::Actinobacteria:Nitrilir... | Bacteria | Actinobacteriota | Actinomycetia | NaN | NaN | NaN | NaN | ... | Nitriliruptoria | FI | 60.426 | 22.992 | 2016-07-25 | 10900290 | NaN | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_3 | POINT (22.99200 60.42600) |
4 | 3916717556 | 7585b2f0-0150-4409-985d-7b57832e3dca | MGYA00198890_Bacteria::Actinobacteria:Actinoba... | Bacteria | Actinobacteriota | Actinomycetia | Mycobacteriales | Pseudonocardiaceae | Allokutzneria | Allokutzneria albata | ... | Allokutzneria albata (Tomita et al., 1993) Lab... | FI | 60.559 | 22.640 | 2016-07-25 | 8374936 | 8374936.0 | GEODETIC_DATUM_ASSUMED_WGS84;CONTINENT_DERIVED... | tipo_2 | POINT (22.64000 60.55900) |
5 rows × 21 columns
# Filtrar observaciones por calidad
filtered_1 = obvs_gdf[obvs_gdf['Categoría'] == 'tipo_1']
filtered_2 = obvs_gdf[obvs_gdf['Categoría'] == 'tipo_2']
filtered_3 = obvs_gdf[obvs_gdf['Categoría'] == 'tipo_3']
# Lienzo
prov_map = fi_mapa
lienzo = prov_map.plot(
figsize=(10, 10),
color="lightgreen",
edgecolor="black",
linewidth=0.5
)
# Título
title = "Zonas muestreadas en Turku, Finlandia"
lienzo.set_title(title)
# Ejes
lienzo.set_xlabel("Longitud")
lienzo.set_ylabel("Latitud")
# Calidades
filtered_1.plot(ax=lienzo, color="red", label='Tipo 1', markersize=40)
filtered_2.plot(ax=lienzo, color="blue", label='Tipo 2', markersize=40)
filtered_3.plot(ax=lienzo, color="green", label='Tipo 3', markersize=40)
# Leyenda
lienzo.legend()
# Ver gráfico
plt.show()
Bioindicadores de calidad del suelo de cafetales de Naranjo, Costa Rica.
------ Filos ------
Calidad Baja: Chloroflexota, GAL15.
Calidad Media: Actinobacteriota, Proteobacteria.
------ Clases ------
Calidad Baja: Acidobacteriae, TK10.
Calidad Media: Actinomycetia, Gitt-GS-136.\
------ Géneros ------
Calidad Baja: HSB OF53-F07, Acidibacter.
Calidad Media: mle1-7, Hyphomicrobium, Pedomicrobium, Gaiella. \
Filos
# Calcular la matriz de contingencia para Filo, muestra el conteo de combinaciones entre dos variables
contingencia = pd.crosstab(df['Categoría'], df['phylum'])
# Convertirla en una matriz de proporciones
proporciones = contingencia.div(contingencia.sum(axis=1), axis=0)
# Calcular la diferencia de proporciones
diferencias = proporciones.iloc[0] - proporciones.iloc[1]
# Seleccionar los 5 valores con mayor diferencia absoluta
top_5_diferencias = diferencias.abs().nlargest(5).index
print("Los 5 filos más distintos son:", top_5_diferencias)
Los 5 filos más distintos son: Index(['Ascomycota', 'Proteobacteria', 'Ciliophora', 'Actinobacteriota', 'Verrucomicrobiota'], dtype='object', name='phylum')
# Filtrar el DataFrame
g_1 = df[df['phylum'] == 'Ascomycota']
g_2 = df[df['phylum'] == 'Proteobacteria']
g_3 = df[df['phylum'] == 'Ciliophora']
g_4 = df[df['phylum'] == 'Actinobacteriota']
g_5 = df[df['phylum'] == 'Verrucomicrobiota']
# Contar la cantidad en cada categoría
conteo_1 = g_1.groupby("Categoría").size()
conteo_2 = g_2.groupby("Categoría").size()
conteo_3 = g_3.groupby("Categoría").size()
conteo_4 = g_4.groupby("Categoría").size()
conteo_5 = g_5.groupby("Categoría").size()
# Combinar los conteos en un solo DataFrame
conteo_combinado = pd.concat([conteo_1, conteo_2, conteo_3, conteo_4, conteo_5], axis=1)
# Renombrar las columnas
conteo_combinado.columns = ['Ascomycota', 'Proteobacteria', 'Ciliophora', 'Actinobacteriota', 'Verrucomicrobiota']
# Tamaño del gráfico
plt.figure(figsize=(10, 20))
# Crear gráfico de barras horizontal
conteo_combinado.plot(kind='barh', color=["#a0d6b4", "#add8e6", "#ffd700", "#ffb6c1", "#dda0dd"])
# Título
plt.title('Frecuencia de los filos más distintos entre categorías')
# Etiqueta del eje Y
plt.ylabel('Categoría')
# Etiqueta del eje X
plt.xlabel('Frecuencia')
# Añadir cuadrícula
plt.grid()
# Mostrar leyenda fuera del gráfico
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
# Ajustar diseño para que la leyenda no se corte
plt.tight_layout()
# Mostrar gráfico
plt.show()
<Figure size 1000x2000 with 0 Axes>
------ Filos de Naranjo ------
Calidad Baja: Chloroflexota, GAL15.
Calidad Media: Actinobacteriota, Proteobacteria
Clases
# Calcular la matriz de contingencia para Clase
contingencia = pd.crosstab(df['Categoría'], df['class'])
# Convertirla en una matriz de proporciones
proporciones = contingencia.div(contingencia.sum(axis=1), axis=0)
# Calcular la diferencia de proporciones
diferencias = proporciones.iloc[0] - proporciones.iloc[1]
# Seleccionar los 5 valores con mayor diferencia absoluta
top_5_diferencias = diferencias.abs().nlargest(5).index
print("Las 5 clases más distintos son:", top_5_diferencias)
Las 5 clases más distintos son: Index(['Actinomycetia', 'Alphaproteobacteria', 'Sordariomycetes', 'Verrucomicrobiae', 'Gammaproteobacteria'], dtype='object', name='class')
# Filtrar el DataFrame
g_1 = df[df['class'] == 'Actinomycetia']
g_2 = df[df['class'] == 'Alphaproteobacteria']
g_3 = df[df['class'] == 'Sordariomycetes']
g_4 = df[df['class'] == 'Verrucomicrobiae']
g_5 = df[df['class'] == 'Gammaproteobacteria']
# Contar la cantidad en cada categoría
conteo_1 = g_1.groupby("Categoría").size()
conteo_2 = g_2.groupby("Categoría").size()
conteo_3 = g_3.groupby("Categoría").size()
conteo_4 = g_4.groupby("Categoría").size()
conteo_5 = g_5.groupby("Categoría").size()
# Combinar los conteos en un solo DataFrame
conteo_combinado = pd.concat([conteo_1, conteo_2, conteo_3, conteo_4, conteo_5], axis=1)
# Renombrar las columnas
conteo_combinado.columns = ['Actinomycetia', 'Alphaproteobacteria', 'Sordariomycetes', 'Verrucomicrobiae', 'Gammaproteobacteria']
# Tamaño del gráfico
plt.figure(figsize=(10, 20))
# Crear gráfico de barras horizontal
conteo_combinado.plot(kind='barh', color=["#a0d6b4", "#add8e6", "#ffd700", "#ffb6c1", "#dda0dd"])
# Título
plt.title('Frecuencia de las clases más distintas entre categorías')
# Etiqueta del eje Y
plt.ylabel('Categoría')
# Etiqueta del eje X
plt.xlabel('Frecuencia')
# Añadir cuadrícula
plt.grid()
# Mostrar leyenda fuera del gráfico
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
# Ajustar diseño para que la leyenda no se corte
plt.tight_layout()
# Mostrar gráfico
plt.show()
<Figure size 1000x2000 with 0 Axes>
------ Clases de Naranjo ------
Calidad Baja: Acidobacteriae, TK10.
Calidad Media: Actinomycetia, Gitt-GS-136.
Géneros
# Calcular la matriz de contingencia para Género
contingencia = pd.crosstab(df['Categoría'], df['genus'])
# Convertirla en una matriz de proporciones
proporciones = contingencia.div(contingencia.sum(axis=1), axis=0)
# Calcular la diferencia de proporciones
diferencias = proporciones.iloc[0] - proporciones.iloc[1]
# Seleccionar los 5 valores con mayor diferencia absoluta
top_5_diferencias = diferencias.abs().nlargest(5).index
print("Los 5 géneros más distintos son:", top_5_diferencias)
Los 5 géneros más distintos son: Index(['Arthrobacter', 'Devosia', 'Ktedonobacter', 'Streptosporangium', 'Actinoplanes'], dtype='object', name='genus')
# Filtrar el DataFrame
g_1 = df[df['genus'] == 'Arthrobacter']
g_2 = df[df['genus'] == 'Devosia']
g_3 = df[df['genus'] == 'Ktedonobacter']
g_4 = df[df['genus'] == 'Streptosporangium']
g_5 = df[df['genus'] == 'Actinoplanes']
# Contar la cantidad en cada categoría
conteo_1 = g_1.groupby("Categoría").size()
conteo_2 = g_2.groupby("Categoría").size()
conteo_3 = g_3.groupby("Categoría").size()
conteo_4 = g_4.groupby("Categoría").size()
conteo_5 = g_5.groupby("Categoría").size()
# Combinar los conteos en un solo DataFrame
conteo_combinado = pd.concat([conteo_1, conteo_2, conteo_3, conteo_4, conteo_5], axis=1)
# Renombrar las columnas
conteo_combinado.columns = ['Arthrobacter', 'Devosia', 'Ktedonobacter', 'Streptosporangium', 'Actinoplanes']
# Tamaño del gráfico
plt.figure(figsize=(10, 20))
# Crear gráfico de barras horizontal
conteo_combinado.plot(kind='barh', color=["#a0d6b4", "#add8e6", "#ffd700", "#ffb6c1", "#dda0dd"])
# Título
plt.title('Frecuencia de los géneros más distintos entre categorías')
# Etiqueta del eje Y
plt.ylabel('Categoría')
# Etiqueta del eje X
plt.xlabel('Frecuencia')
# Añadir cuadrícula
plt.grid()
# Mostrar leyenda fuera del gráfico
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
# Ajustar diseño para que la leyenda no se corte
plt.tight_layout()
# Mostrar gráfico
plt.show()
<Figure size 1000x2000 with 0 Axes>
------ Géneros de Naranjo ------
Calidad Baja: HSB OF53-F07, Acidibacter.
Calidad Media: mle1-7, Hyphomicrobium, Pedomicrobium, Gaiella. \
# Filtrar el DataFrame por los géneros de Naranjo con mayor diferencia entre categorías.
aci_g = df[df['genus'] == 'Acidibacter']
hyp_g = df[df['genus'] == 'Hyphomicrobium']
# Contar la cantidad en cada categoría
conteo_aci_g = aci_g.groupby("Categoría").size()
conteo_hyp_g = hyp_g.groupby("Categoría").size()
# Combinar los conteos en un solo DataFrame
conteo_combinado = pd.concat([conteo_aci_g, conteo_hyp_g], axis=1)
# Renombrar las columnas
conteo_combinado.columns = ['Acidibacter', 'Hyphomicrobium']
# Tamaño del gráfico
plt.figure(figsize=(10, 10))
# Crear gráfico de barras horizontal
conteo_combinado.plot(kind='barh', color=["#a0d6b4", "#dda0dd"])
# Título
plt.title('Frecuencia de los géneros Hyphomicrobium y Acidibacter entre categorías')
# Etiqueta del eje Y
plt.ylabel('Categoría')
# Etiqueta del eje X
plt.xlabel('Frecuencia')
# Añadir cuadrícula
plt.grid()
# Mostrar leyenda fuera del gráfico
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
# Ajustar diseño para que la leyenda no se corte
plt.tight_layout()
# Mostrar gráfico
plt.show()
<Figure size 1000x1000 with 0 Axes>
Conclusiones:¶
• El dataset tiene poca información que permita analizar adecuadamente los suelos considerados saludables y no saludables, debido a que no se indican esas categorías para los datos, pero para realizar el ejercicio funcionó muy bien, debido a que se logró filtrar y limpiar la información.
• Es evidente que las muestras procesadas en los tres sitios de Finlandia, presentan diferencias en la estructura del microbioma del suelo.
• El género fue el nivel taxonómico con mayor resolución para representar las diferencias entre los tres sitios, brindando un análisis más detallado.
• A pesar de que se esperaba que la estructura de los microorganismos del suelo de Costa Rica y Finlandia fuera muy diferente, por su naturaleza y método de análisis; se presentan similitudes en la importancia de taxones como Proteobacteria, Actinobacteriota y Actinomycetia.
Referencias:¶
Berihu, M., Somera, T. S., Malik, A., Medina, S., Piombo, E., Tal, O., ... & Freilich, S. (2023). A framework for the targeted recruitment of crop-beneficial soil taxa based on network analysis of metagenomics data. Microbiome, 11(1), 8.
Edwin, N. R., Fitzpatrick, A. H., Brennan, F., Abram, F., & O’Sullivan, O. (2024). An in-depth evaluation of metagenomic classifiers for soil microbiomes. Environmental Microbiome, 19(1), 19.
Hermans, S. M., Buckley, H. L., Case, B. S., Curran-Cournane, F., Taylor, M., & Lear, G. (2020). Using soil bacterial communities to predict physico-chemical variables and soil quality. Microbiome, 8, 1-13.
Instituto Nacional de Tecnología Agropecuaria. (2019). Zonificación Agroecológica para el cantón de Naranjo de Alajuela. Recuperado de http://www.platicar.go.cr/images/buscador/documents/pdf/2019/Memoria_Tecnica_NARANJO_Comp_ed.pdf \
MGnify (2020). Soil metagenome from healthy and unhealthy agricultural soil. Sampling event dataset https://doi.org/10.15468/rguc4r accessed via GBIF.org on 2024-06-04.
Plassart, P., Prévost-Bouré, N. C., Uroz, S., Dequiedt, S., Stone, D., Creamer, R., ... & Lemanceau, P. (2019). Soil parameters, land use, and geographical distance drive soil bacterial communities along a European transect. Scientific reports, 9(1), 1-17.