<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Matheus Halmenschlager]]></title><description><![CDATA[Cientista e analista de dados, devoto de Python, e biólogo (só) nas horas vagas.]]></description><link>https://blog.matheusyuri.pro</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1625790176084/BylM2-EhC.png</url><title>Matheus Halmenschlager</title><link>https://blog.matheusyuri.pro</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 11 Apr 2026 08:46:30 GMT</lastBuildDate><atom:link href="https://blog.matheusyuri.pro/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[ATC/DDD na Ponta dos Dedos: Extração de Dados com Web Scraping]]></title><description><![CDATA[Na época da escola, se você ainda se lembra, estudamos nas aulas de Biologia uma coisa chamada taxonomia. Você lembra o que é?
Basicamente, a taxonomia é uma ciência que se dedica a organizar os seres]]></description><link>https://blog.matheusyuri.pro/atc-ddd-na-ponta-dos-dedos-extra-o-de-dados-com-web-scraping</link><guid isPermaLink="true">https://blog.matheusyuri.pro/atc-ddd-na-ponta-dos-dedos-extra-o-de-dados-com-web-scraping</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[web scraping]]></category><category><![CDATA[web scraper ]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[Databases]]></category><category><![CDATA[Clinical Research]]></category><category><![CDATA[Clinical Data Management ]]></category><category><![CDATA[clinical trials]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Mon, 23 Feb 2026 13:48:47 GMT</pubDate><enclosure url="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/60e725744e18000309d8123a/90a6ffe8-554d-488a-b776-6fa9147d028a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Na época da escola, se você ainda se lembra, estudamos nas aulas de Biologia uma coisa chamada <em>taxonomia</em>. Você lembra o que é?</p>
<p>Basicamente, a taxonomia é uma ciência que se dedica a organizar os seres vivos de forma hierárquica, considerando caracteres comuns entre eles. A cada nível hierárquico que se avança, mais específico é o grupo (ou, nesse caso, <em>táxon</em>) onde o organismo de interesse estará alocado.</p>
<p>Embora esse conceito seja mais conhecido quando aplicado à classificação dos seres vivos, é possível adotar o mesmo conceito para vários outros grupos. Ao identificarmos padrões, por exemplo, em prefixos do transporte público, placas de carros, números de série de vários utensílios, vemos na prática as possibilidades de organização de tudo o que está ao nosso redor baseando-se em suas características, desde as mais comuns, chegando até o caractere mais específico possível, o mais único para aquele objeto de interesse.</p>
<p>Na pesquisa clínica, também não é diferente. Dentre muitos padrões relacionados às boas práticas preconizadas pelas maiores autoridades na área, alguns sistemas de codificação estão presentes. Um bom exemplo é a classificação ATC, que é o foco deste artigo.</p>
<p>A Classificação <strong>ATC</strong> (<em>Anatomical Therapeutic Chemical Code</em>) é uma referência internacional utilizada para catalogar substâncias com ação terapêutica. Isso inclui, por exemplo, medicamentos usados diariamente para aliviar ou tratar uma ampla variedade de doenças. Nos estudos clínicos, a classificação ATC é considerada o padrão-ouro para o monitoramento e pesquisa de diversos medicamentos administráveis.</p>
<h2>A Taxonomia do ATC</h2>
<p>Assim como em uma classificação biológica, o ATC também começa de um universo mais amplo (o grupo anatômico) rumo a grupos mais específicos (classes de medicamentos, grupos de moléculas, entre outros); o que diferencia é que, basicamente, em vez de um nome latino (como <em>Canis lupus familiaris</em> para os cães domésticos), o ATC retorna um código sequencial, refletindo cada grupo o qual aquela substância terapêutica pertence.</p>
<p>Esse código sequencial é dividido em cinco níveis, a saber:</p>
<ol>
<li><p><strong>Nível 1 – Domínio</strong> ou <strong>Grupo Anatômico</strong> (letra inicial, ex.: A, B, C)</p>
</li>
<li><p><strong>Nível 2 – Subgrupo terapêutico principal</strong> (ex.: A10 – Drogas usadas no diabetes)</p>
</li>
<li><p><strong>Nível 3 – Subgrupo terapêutico/farmacológico</strong> (ex.: A10B)</p>
</li>
<li><p><strong>Nível 4 – Subgrupo químico/terapêutico/farmacológico</strong> (ex.: A10BA)</p>
</li>
<li><p><strong>Nível 5 – Substância química</strong> (ex.: A10BA02 – Metformina, com DDD, dose, via, etc.)</p>
</li>
</ol>
<img src="https://i.ibb.co/LDkdNkVP/mermaid-diagram-2025-04-01-132539.png" alt="" />

<h2>O que será feito aqui</h2>
<p>Organizando nossos pensamentos e ações, isto é o que será feito nesse artigo:</p>
<ul>
<li><p>Acesso à página da lista ATC;</p>
</li>
<li><p>Reconhecimento dos dados de interesse, através da identificação e entendimento da estrutura em HTML da página;</p>
</li>
<li><p><em>Web scraping</em> dos dados;</p>
</li>
<li><p>Armazenamento dos dados raspados em um arquivo estruturado (no caso, um arquivo Excel).</p>
</li>
</ul>
<h2>Como os dados de interesse estão dispostos na página oficial: entendendo o HTML</h2>
<p>Se você chegou até aqui e sabe pouco, ou não tem a mínima ideia do que seja HTML, eis o que você precisa saber para continuar: HTML, sigla para <em>HyperText Markup Language</em>, é, como o nome diz, uma linguagem de <em>marcação</em>. Ela serve para definir a estrutura e o significado de uma página web. Imagine o esqueleto de um ser vivo; assim como os ossos são dispostos a definir o formato de um corpo, as <em>tags</em> HTML ajudam a definir a estrutura de uma página.</p>
<p>A imagem abaixo demonstra exemplos de <em>tags</em> que nós podemos encontrar em um texto HTML; à medida em que formos explorando o conteúdo das páginas web, reconheceremos a função de algumas tags mostradas aqui.</p>
<img src="https://www.csschopper.com/blog/wp-content/uploads/2011/07/Important-HTML-Tags.png" alt="" />

<h3>Como acessar a estrutura HTML de um site para ver as tags</h3>
<p>Uma vez que sabemos da existência de uma estrutura HTML para um site, antes de partirmos à extração de dados propriamente dita, é interessante que tenhamos conhecimentos de meios de ver a estrutura de um site; assim, quando formos colocar a mão na massa, podemos sempre recorrer a uma fonte contínua que mostre as tags que compõem a página.</p>
<p>Os <em>browsers</em> que são mais utilizados atualmente costumam ter um recurso chamado 'Inspecionar', que pode ser acessado pela lista de opções que aparece quando se pressiona o botão direito do mouse. Como o próprio nome já diz, o recurso serve para fazer uma verificação mais profunda na estrutura da página que está sendo vista.</p>
<p>Uma vez selecionado o 'Inspecionar', aparecerá uma janela à parte em seu navegador. O que interessa para essa prática está em uma aba que tem variados nomes, como 'Inspetor' ou 'Elementos'. É possível identificar do que se trata ao ver as várias linhas de código que saltam aos olhos; compare com os exemplos que já foram dados, e você logo perceberá que se trata da estrutura HTML, ou não.</p>
<p>![](<a href="https://i.ibb.co/0pb9hTc3/Captura-de-tela-2026-02-23-102913.png">https://i.ibb.co/0pb9hTc3/Captura-de-tela-2026-02-23-102913.png</a> align="middle")</p>
<p>Com esse conhecimento em mãos, já podemos começar a usar o Python para acessar as páginas de interesse, e extrair os dados que estão nelas.</p>
<h2>Utilizando Python para fazer o <em>web scraping</em></h2>
<p>Para esta parte, precisaremos importar uma série de bibliotecas que serão as responsáveis por acessarmos as páginas, extrairmos os dados e, por fim, adicionarmos tudo a uma planilha, que dará sentido a tudo o que fizermos.</p>
<pre><code class="language-python">import requests
from bs4 import BeautifulSoup as BS
import string, re
import pandas as pd
import numpy as np
import gc
from time import sleep
</code></pre>
<ul>
<li><p><a href="https://requests.readthedocs.io/en/latest/"><strong>Requests</strong></a> <strong>- HTTP para seres humanos</strong></p>
</li>
<li><p><a href="https://docs.python.org/pt-br/3/library/re.html"><strong>re</strong></a> <strong>- Operações com REGEX (Expressões regulares)</strong></p>
</li>
<li><p><a href="https://docs.python.org/3/library/string.html"><strong>string</strong></a> <strong>- Operações com strings (sequência de caracteres)</strong></p>
</li>
<li><p><a href="https://pandas.pydata.org/"><strong>pandas</strong></a> <strong>- A biblioteca de análise de dados mais usada em Python</strong></p>
</li>
<li><p><a href="https://numpy.org/"><strong>numpy</strong></a> <strong>- A principal biblioteca Python para computação científica</strong></p>
</li>
<li><p><a href="https://beautiful-soup-4.readthedocs.io/en/latest/"><strong>BeautifulSoup</strong></a> <strong>- Para extrair dados em HTML</strong></p>
</li>
<li><p><a href="https://docs.python.org/3/library/gc.html"><strong>gc</strong></a> <strong>- O <em>garbage collector</em> do Python, para administrar a memória utilizada</strong></p>
</li>
<li><p><a href="https://docs.python.org/3/library/time.html"><strong>time</strong></a> <strong>- Para tudo que envolve tempo</strong></p>
</li>
</ul>
<h2>Reconhecendo o que existe no site do ATC</h2>
<p>A primeira coisa que faremos antes de começarmos a extrair os dados é entender como o site do ATC/DDD Index está estruturado. Para tanto, será preciso acessar o site <a href="https://atcddd.fhi.no/atc%5C_ddd%5C_index/">https://atcddd.fhi.no/atc\_ddd\_index/</a> . A imagem abaixo indica o que vamos encontrar ao acessar o link.</p>
<p>![](<a href="https://i.ibb.co/Wh9VXQj/Screenshot-2026-02-17-at-07-11-02-ATCDDD-ATC-DDD-Index.png">https://i.ibb.co/Wh9VXQj/Screenshot-2026-02-17-at-07-11-02-ATCDDD-ATC-DDD-Index.png</a> align="middle")</p>
<p>Ao usarmos o recurso 'Inspecionar' do <em>browser</em>, teremos acesso a cada detalhe da estrutura HTML, que é o que realmente importa aqui. Com isso já em mãos, podemos seguir para a escrita do código.</p>
<h2>Construindo uma função de requisição (e evitando possíveis problemas)</h2>
<p>Para fazer a raspagem dos dados, a construção do <em>script</em> será orientada por funções; isso será feito baseado no princípio de que a modularização facilita a legibilidade, manutenção, e reusabilidade do código.</p>
<p>A primeira função a ser criada é uma das mais importantes do <em>script</em> inteiro:</p>
<pre><code class="language-python">def get_page_content(url, retries=3, delay=0.5):
    """Função para fazer requisições com retry e delay"""
    for attempt in range(retries):
        try:
            response = requests.get(url, timeout=10)
            sleep(delay)  # Evita sobrecarregar o servidor
            return response.content
        except requests.RequestException as e:
            if attempt == retries - 1:
                print(f"Erro ao acessar {url}: {e}")
                return None
            sleep(delay * (attempt + 1))
    return None
</code></pre>
<p>O que temos aqui é uma função responsável por fazer as requisições ao site do ATC/DDD, construída de uma maneira que previna alguns problemas que podem ocorrer quando exploramos de forma automática páginas web.</p>
<ul>
<li><p><code>requests.get</code> <strong>com</strong> <code>timeout</code>: evita que o código fique travado indefinidamente.</p>
</li>
<li><p><strong>Retry com backoff (</strong><code>delay * (attempt + 1)</code><strong>)</strong>: trata instabilidades temporárias da rede ou do servidor, insistindo no código apenas depois de um tempo.</p>
</li>
<li><p><strong>Pequenos</strong> <code>sleep</code><strong>s</strong>: respeita o servidor, reduz risco de um possível bloqueio por parte do servidor; isso poderia acontecer se fossem feitas muitas requisições em um período curto de tempo, o que poderia gerar uma sobrecarga no servidor, tornando o conteúdo do site indisponível para acesso.</p>
</li>
</ul>
<h2>Identificando os grupos anatômicos (nível 1)</h2>
<p>O primeiro nível do ATC usa letras simples de A a Z, mas nem todas são válidas. A partir disso, uma função que itera por todo o alfabeto (usando o <code>string.ascii_uppercase</code>) é construída, e usa a presença de uma tag <code>&lt;h2&gt;</code> na resposta como sinal de que aquela letra não corresponde a um grupo existente.</p>
<p>![](<a href="https://i.ibb.co/fGD21fb5/Screenshot-2026-02-23-at-10-31-25-ATCDDD-ATC-DDD-Index.png">https://i.ibb.co/fGD21fb5/Screenshot-2026-02-23-at-10-31-25-ATCDDD-ATC-DDD-Index.png</a> align="middle")</p>
<pre><code class="language-python">def extract_domain_codes():
    """Extrai códigos de domínio (nível 1)"""
    print("Extraindo códigos de domínio...")
    results = []

    for letter in string.ascii_uppercase:
        content = get_page_content(f'https://atcddd.fhi.no/atc_ddd_index/?code={letter}&amp;showdescription=no')
        if not content:
            continue

        soup = BS(content, 'html.parser')
        if soup.find('h2'):
            print(f'{letter} inválido')
        else:
            print(f'{letter} válido')
            try:
                link = soup.find('b').find('a')
                code = re.search('[A-Z]', link['href']).group(0)
                name = link.text.strip()
                results.append({'code': code, 'name': name, 'level': 1})
            except (AttributeError, TypeError):
                print(f"Erro ao processar {letter}")

    return pd.DataFrame(results)
</code></pre>
<p>O <code>BeautifulSoup</code> faz o parsing do HTML bruto retornado pelo <code>requests</code>, e o <code>re</code> (regex) extrai o código ATC do atributo <code>href</code> do link. Esse padrão de usar regex nos hrefs ao invés de depender do texto visível é mais robusto, porque o texto pode variar, mas a estrutura da URL tende a ser consistente. Ainda vale destacar a atribuição de um <em>nível hieráquico</em> para cada resultado, assim como é estabelecido no ATC/DDD; nesse caso, o nível atribuído é o número <code>1</code>. A mesma coisa será feita para os níveis seguintes.</p>
<p>O resultado final é uma lista de dicionários que, usando o <code>pandas</code>, se tornará um <code>DataFrame</code>, que estará pronto para ser exportado no final de tudo.</p>
<h2>Identificando os grupos terapêuticos (nível 2)</h2>
<p>Aqui entra um ponto de autoridade importante: <strong>a preservação da hierarquia.</strong> Isso quer dizer que, para alcançar os códigos seguintes, será preciso considerar o código do nível anterior. Assim:</p>
<ul>
<li><p>Para cada domínio (nível 1), você acessa novamente o site. Uma vez que já temos os domínios válidos, serão acessados apenas estes.</p>
</li>
<li><p>Usa regex para encontrar códigos <code>[A-Z][0-9]+</code> dentro dos links. Isso porque, em cada link de domínio, aparece uma lista com os códigos do nível seguinte.</p>
</li>
<li><p>Relaciona cada código de nível 2 com o <em>parent_code</em> (a letra do domínio). Exemplo: para o domínio <code>A</code>, estarão relacionados os códigos de nível 2 <code>A01</code>, <code>A02</code>, e assim por diante.</p>
</li>
</ul>
<p>![](<a href="https://i.ibb.co/xtQwy5z3/Screenshot-2026-02-23-at-10-32-33-ATCDDD-ATC-DDD-Index.png">https://i.ibb.co/xtQwy5z3/Screenshot-2026-02-23-at-10-32-33-ATCDDD-ATC-DDD-Index.png</a> align="middle")</p>
<p>Esse <code>parent_code</code> é crucial: ele permite, mais tarde, reconstruir a árvore completa sem precisar “chutar” ligações. Essa preocupação com hierarquia torna seu scraping <em>analiticamente útil</em>, não apenas uma extração bruta de texto.</p>
<pre><code class="language-python">def extract_therapeutic_subgroups(domain_codes):
    """Extrai subgrupos terapêuticos (nível 2)"""
    print("Extraindo subgrupos terapêuticos...")
    results = []

    for _, row in domain_codes.iterrows():
        letter = row['code']
        content = get_page_content(f'https://atcddd.fhi.no/atc_ddd_index/?code={letter}&amp;showdescription=no')
        if not content:
            continue

        soup = BS(content, 'html.parser')
        for b_tag in soup.find_all('b'):
            try:
                link = b_tag.find('a')
                if not link:
                    continue

                code_match = re.search('[A-Z][0-9]+', link['href'])
                if code_match:
                    code = code_match.group(0)
                    name = link.text.strip()
                    # Relaciona com o domínio pai
                    parent_code = code[0]  # Primeiro caractere é o código do domínio
                    results.append({
                        'code': code,
                        'name': name,
                        'parent_code': parent_code,
                        'level': 2
                    })
            except (AttributeError, TypeError):
                continue

    return pd.DataFrame(results).drop_duplicates(subset=['code'])
</code></pre>
<h2>Identificando subgrupos farmacológicos (nível 3) e químicos (nível 4)</h2>
<p>Para os próximos dois níveis, 3 e 4, a lógica de preservação e relação com hierarquias segue sendo utilizada, mas com algumas diferenças para cada subgrupo, devido a suas peculiaridades. Vejamos:</p>
<pre><code class="language-python">def extract_pharmacological_subgroups(therap_subgroups):
    """Extrai subgrupos farmacológicos (nível 3)"""
    print("Extraindo subgrupos farmacológicos...")
    results = []

    for _, row in therap_subgroups.iterrows():
        code = row['code']
        content = get_page_content(f'https://atcddd.fhi.no/atc_ddd_index/?code={code}&amp;showdescription=no')
        if not content:
            continue

        soup = BS(content, 'html.parser')
        for b_tag in soup.find_all('b'):
            try:
                link = b_tag.find('a')
                if not link:
                    continue

                code_match = re.search('[A-Z][0-9]{2}[A-Z]', link['href'])
                if code_match:
                    new_code = code_match.group(0)
                    name = link.text.strip()
                    parent_code = new_code[:3]  # ex.: A10
                    results.append({
                        'code': new_code,
                        'name': name,
                        'parent_code': parent_code,
                        'level': 3
                    })
            except (AttributeError, TypeError):
                continue

    gc.collect()
    return pd.DataFrame(results).drop_duplicates(subset=['code'])
</code></pre>
<pre><code class="language-python">def extract_chemical_subgroups(pharm_subgroups):
    """Extrai subgrupos químicos (nível 4)"""
    print("Extraindo subgrupos químicos...")
    results = []

    for _, row in pharm_subgroups.iterrows():
        code = row['code']
        content = get_page_content(f'https://atcddd.fhi.no/atc_ddd_index/?code={code}&amp;showdescription=no')
        if not content:
            continue

        soup = BS(content, 'html.parser')
        for b_tag in soup.find_all('b'):
            try:
                link = b_tag.find('a')
                if not link:
                    continue

                code_match = re.search('[A-Z][0-9]{2}[A-Z]{2}', link['href'])
                if code_match:
                    new_code = code_match.group(0)
                    name = link.text.strip()
                    parent_code = new_code[:4]  # ex.: A10B
                    results.append({
                        'code': new_code,
                        'name': name,
                        'parent_code': parent_code,
                        'level': 4
                    })
            except (AttributeError, TypeError):
                continue

    gc.collect()
    return pd.DataFrame(results).drop_duplicates(subset=['code'])
</code></pre>
<p>Aqui, o que vale destacar é o seguinte:</p>
<ul>
<li><p><strong>Há expressões regulares específicas</strong> para cada nível. Nesta altura, se sobressai o conhecimento da estrutura do ATC/DDD, indicando exatamente como cada código está disposto conforme seu nível.</p>
</li>
<li><p><strong>Construção sistemática do</strong> <code>parent_code</code> por fatiamento de string.</p>
</li>
<li><p>Uso de <code>gc.collect()</code> para aliviar memória, uma preocupação que aparece em scrapers que percorrem muitas páginas. Isso se torna essencial quando vamos lidar com <em>scripts</em> como esse em máquinas cuja memória é bastante limitada. O que não está sendo mais utilizado é excluído com segurança, de modo que, a cada etapa passada, não seja comprometida tanta memória a ponto de travar a atividade.</p>
</li>
</ul>
<p>Essa disciplina de padrões e relacionamentos é o que transforma o código em <em>infraestrutura de dados</em>, não apenas em um script pontual para extrair informação de um dado local.</p>
<p>![](<a href="https://i.ibb.co/nMxMNTyd/Screenshot-2026-02-23-at-10-33-48-ATCDDD-ATC-DDD-Index.png">https://i.ibb.co/nMxMNTyd/Screenshot-2026-02-23-at-10-33-48-ATCDDD-ATC-DDD-Index.png</a> align="middle")</p>
<h2>Identificando as substâncias químicas (nível 5) e dados complementares</h2>
<p>![](<a href="https://i.ibb.co/PvHL5jKB/Screenshot-2026-02-23-at-10-35-20-ATCDDD-ATC-DDD-Index.png">https://i.ibb.co/PvHL5jKB/Screenshot-2026-02-23-at-10-35-20-ATCDDD-ATC-DDD-Index.png</a> align="middle")</p>
<p>Essa é a parte final de extração de dados da página do ATC/DDD, e a que possui maior riqueza de detalhes. Aqui, além do código ATC por inteiro, faremos a extração do DDD, da unidade da dose, a via de administração, além de possíveis observações. Para tanto, precisamos considerar primeiramente um ponto em específico:</p>
<p><em>Alguns códigos não possuirão dados como a dose, a unidade de dose, e a via de administração. Para esses casos, precisaremos fazer um tratamento de dados faltantes, visando evitar possíveis quebras de linha que bagunçariam o resultado final.</em></p>
<p>Isso será feito da seguinte maneira:</p>
<ul>
<li><p>Trataremos explicitamente células vazias que vêm como <code>'\xa0'</code><a href="https://www.codetable.net/hex/a0">(espaço não separável em HTML).</a></p>
</li>
<li><p>Substituiremos essas células por <code>np.nan</code> (do NumPy), que é o padrão industrial para representar missing values em análises numéricas.</p>
</li>
<li><p>Manteremos <code>dose</code>, <code>unit</code>, <code>admin</code>, <code>note</code> bem separados – isso facilita desde análise estatística até construção de dicionários de medicamentos. A célula que tiver dado ausente será representada por um <code>nan</code>, assim garantindo a representação de todas as colunas.</p>
</li>
</ul>
<pre><code class="language-python">def extract_chemical_substances(chem_subgroups):
    """Extrai substâncias químicas (nível 5)"""
    print("Extraindo substâncias químicas...")
    results = []

    for _, row in chem_subgroups.iterrows():
        code = row['code']
        print(f'Processando dados de {code}')

        content = get_page_content(f'https://atcddd.fhi.no/atc_ddd_index/?code={code}&amp;showdescription=no')
        if not content:
            continue

        soup = BS(content, 'html.parser')
        table = soup.find('table')

        if table:
            for tr in table.find_all('tr'):
                tds = tr.find_all('td')
                if len(tds) &gt;= 6:  # Garante que temos todas as colunas
                    try:
                        atc_match = re.search('[A-Z][0-9]{2}[A-Z]{2}[0-9]{2}', tds[0].text)
                        if atc_match:
                            substance_code = atc_match.group(0)
                            name = tds[1].text.strip()
                            dose = tds[2].text.strip() if tds[2].text.strip() != '\xa0' else np.nan
                            unit = tds[3].text.strip() if tds[3].text.strip() != '\xa0' else np.nan
                            admin = tds[4].text.strip() if tds[4].text.strip() != '\xa0' else np.nan
                            note = tds[5].text.strip() if tds[5].text.strip() else np.nan

                            parent_code = substance_code[:5]  # ex.: A10BA

                            results.append({
                                'code': substance_code,
                                'name': name,
                                'dose': dose,
                                'unit': unit,
                                'admin': admin,
                                'note': note,
                                'parent_code': parent_code,
                                'level': 5
                            })
                    except (IndexError, AttributeError):
                        continue

    gc.collect()
    return pd.DataFrame(results).drop_duplicates(subset=['code'], keep='last')
</code></pre>
<h2>Juntando tudo e construindo a árvore final: das páginas do ATC/DDD para uma estrutura de dados</h2>
<p>Uma vez realizadas as coletas em todos os níveis de código ATC e dados complementares, chegamos à parte mais crítica do código: juntar todos os resultados em um <code>DataFrame</code> estruturado, observando sempre a preservação das hirearquias entre níveis.</p>
<p>Isso será feito usando os seguintes passos:</p>
<ul>
<li><p><strong>Performando joins hierárquicos em pandas</strong> usando colunas derivadas (<code>str[:4]</code>, <code>str[:3]</code>, etc.).</p>
</li>
<li><p>Uso de <code>how='left'</code> para não perder nenhuma substância mesmo que alguma descrição de nível superior falte.</p>
</li>
<li><p>Renomear colunas para nomes sem ambiguidade (<code>chemical_name</code>, <code>therapeutic_name</code>, etc.).</p>
</li>
</ul>
<p>O resultado será um <code>DataFrame</code> onde cada linha representa <strong>uma substância química</strong>, acompanhada de:</p>
<ul>
<li><p>Domínio (nível 1)</p>
</li>
<li><p>Subgrupo terapêutico (nível 2)</p>
</li>
<li><p>Subgrupo farmacológico (nível 3)</p>
</li>
<li><p>Subgrupo químico (nível 4)</p>
</li>
<li><p>Dados de DDD, unidade, via, nota (nível 5)</p>
</li>
</ul>
<pre><code class="language-python">def build_hierarchical_structure(level1, level2, level3, level4, level5):
    """Constrói a estrutura hierárquica de forma eficiente"""
    print("Construindo estrutura hierárquica...")

    # Para o nível 5, fazemos joins hierárquicos diretos
    result = level5.copy()

    # Join com nível 4
    level4_slim = level4[['code', 'name']].rename(columns={'code': 'parent_code', 'name': 'chemical_name'})
    result = result.merge(level4_slim, on='parent_code', how='left')

    # Join com nível 3
    result['pharm_parent'] = result['parent_code'].str[:4]
    level3_slim = level3[['code', 'name']].rename(columns={'code': 'pharm_parent', 'name': 'pharmacological_name'})
    result = result.merge(level3_slim, on='pharm_parent', how='left')

    # Join com nível 2
    result['therap_parent'] = result['pharm_parent'].str[:3]
    level2_slim = level2[['code', 'name']].rename(columns={'code': 'therap_parent', 'name': 'therapeutic_name'})
    result = result.merge(level2_slim, on='therap_parent', how='left')

    # Join com nível 1
    result['domain_parent'] = result['therap_parent'].str[:1]
    level1_slim = level1[['code', 'name']].rename(columns={'code': 'domain_parent', 'name': 'domain_name'})
    result = result.merge(level1_slim, on='domain_parent', how='left')

    # Limpa colunas auxiliares
    result = result.drop(['parent_code', 'level', 'pharm_parent', 'therap_parent', 'domain_parent'], axis=1)

    return result
</code></pre>
<p>O <code>DataFrame</code> que surge de resultado é, basicamente, uma tabela bem estruturada, que considera todos os níveis de código do ATC e os junta de uma forma facilmente entendível. Esse resultado está pronto para ser utilizado de várias formas; vejamos alguns exemplos:</p>
<ul>
<li><p>Modelos de classificação de medicamentos</p>
</li>
<li><p>Consolidação de bases de prescrição</p>
</li>
<li><p>Integrações com sistemas regulatórios</p>
</li>
<li><p>Dashboards de consumo/uso de medicamentos</p>
</li>
</ul>
<h2><em>La grande finale</em>: o pipeline completo em Python</h2>
<p>No final de tudo, todos as funções que já foram criadas serão incluídas em um único pipeline, na função <code>main()</code>, dividido em etapas lógicas que invocam cada nível do código em seu momento oportuno. Além disso, a função conta com logs que informam diretamente no console quantos registros foram extraídos em cada nível percorrido.</p>
<p>Todos os dados extraídos e organizados são finalmente consolidados em um arquivo Excel (<code>.xlsx</code>), valendo-se da função do <code>pandas</code> apropriada para a atividade; esse arquivo estará pronto para o consumo e verificação de qualquer usuário. Ainda, há o tratamento de possíveis exceções em uma escala global: basicamente, o <em>script</em> avisa qual exatamente foi o erro que ocorreu durante a sua execução, tornando a resolução mais rápida e assertiva.</p>
<pre><code class="language-python">def main():
    """Função principal otimizada"""
    try:
        # Extrai dados nível por nível
        level1 = extract_domain_codes()
        print(f"Nível 1: {len(level1)} registros")

        level2 = extract_therapeutic_subgroups(level1)
        print(f"Nível 2: {len(level2)} registros")

        level3 = extract_pharmacological_subgroups(level2)
        print(f"Nível 3: {len(level3)} registros")

        level4 = extract_chemical_subgroups(level3)
        print(f"Nível 4: {len(level4)} registros")

        level5 = extract_chemical_substances(level4)
        print(f"Nível 5: {len(level5)} registros")

        # Constrói estrutura final
        final_result = build_hierarchical_structure(level1, level2, level3, level4, level5)

        # Salva resultado
        output_file = "PATH/Lista_ATC_COMPLETA_Otimizada.xlsx" #Adapte para o caminho em sua máquina onde o arquivo será salvo.
        final_result.to_excel(output_file, index=False)
        print(f"Dados salvos em: {output_file}")
        print(f"Total de registros finais: {len(final_result)}")

        return final_result

    except Exception as e:
        print(f"Erro durante execução: {e}")
        return None
</code></pre>
<p>![](<a href="https://media.licdn.com/dms/image/v2/D4D22AQFavuRHlYMFWQ/feedshare-shrink_2048_1536/B4DZxw6uiiJIAk-/0/1771420969458?e=1773273600&amp;v=beta&amp;t=aEC4OnT7zl4JKdsu-7AElNqhl4KEpoc1qqu0iZRlwjY">https://media.licdn.com/dms/image/v2/D4D22AQFavuRHlYMFWQ/feedshare-shrink_2048_1536/B4DZxw6uiiJIAk-/0/1771420969458?e=1773273600&amp;v=beta&amp;t=aEC4OnT7zl4JKdsu-7AElNqhl4KEpoc1qqu0iZRlwjY</a> align="middle")</p>
<h2>Insights valiosos sobre web scraping em contextos como o apresentado</h2>
<ol>
<li><p><strong>Scraping não é só “raspar HTML” — é modelar o domínio de negócio</strong><br />Ao preservar a hierarquia (parent codes, níveis 1 a 5) e organizar os dados em um modelo coerente, estamos traduzindo a lógica regulatória do sistema ATC para um modelo de dados. Isso permite análises complexas (por domínio terapêutico, por via de administração, por dose definida diária) com rastreabilidade total até a fonte oficial.</p>
</li>
<li><p><strong>Requests + BeautifulSoup + pandas + numpy formam um stack poderoso para dados regulatórios</strong></p>
<ul>
<li><p><code>requests</code>: acesso controlado, com timeout e retries.</p>
</li>
<li><p><code>BeautifulSoup</code>: extração precisa e legível de conteúdo HTML.</p>
</li>
<li><p><code>pandas</code>: manipulação de tabelas, joins hierárquicos, limpeza.</p>
</li>
<li><p><code>numpy</code>: representação rigorosa de valores ausentes e numéricos.</p>
</li>
</ul>
<p>Dominar esse conjunto significa ir além do Excel e ter controle total sobre a <em>linha de produção</em> dos dados farmacêuticos.</p>
</li>
<li><p><strong>Eficiência e respeito ao servidor fazem parte da reputação técnica</strong><br />O uso de pausa entre requisições, retries controlados, limpeza de memória e filtragem por regex minimiza carga no servidor, reduz falhas e aumenta a confiabilidade do processo. Em contextos sensíveis como saúde, isso é mais do que uma boa prática de código — é um requisito ético e profissional, ainda mais em contextos em que ainda usamos recursos limitados para fazer análises mais complexas.</p>
</li>
</ol>
<p>Agora, imagine: Se você tivesse hoje a hierarquia ATC/DDD completa e atualizada nesse formato tabular, qual seria a primeira análise ou automação de alto impacto que você implementaria com esses dados na sua realidade (por exemplo, na área clínica, regulatória, de mercado ou de pesquisa)? E, com os conhecimentos sobre web scraping passados aqui, quais possibilidades você já enxerga de extração de dados para auxiliar em outras análises, considerando o tempo e energia economizados para suas análises do dia-a-dia?</p>
]]></content:encoded></item><item><title><![CDATA[Aula 10.3 - Análise e visualização de dados em Python - biblioteca pandas (parte 8)]]></title><description><![CDATA[Nas últimas aulas desta série, vimos o poder do pandas para fazer junções de diferentes fontes de dados, facilitando assim a vida de quem tem precisado lidar com tabelas fragmentadas. Até o momento, discutimos com mais detalhes as funções concat() e ...]]></description><link>https://blog.matheusyuri.pro/aula-103-analise-e-visualizacao-de-dados-em-python-biblioteca-pandas-parte-8</link><guid isPermaLink="true">https://blog.matheusyuri.pro/aula-103-analise-e-visualizacao-de-dados-em-python-biblioteca-pandas-parte-8</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[#ecology]]></category><category><![CDATA[Databases]]></category><category><![CDATA[pandas]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Tue, 07 Jan 2025 18:33:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735912134565/a40a4932-341b-4d51-ba48-d287955d37b0.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Nas últimas aulas desta série, vimos o poder do <code>pandas</code> para fazer junções de diferentes fontes de dados, facilitando assim a vida de quem tem precisado lidar com tabelas fragmentadas. Até o momento, discutimos com mais detalhes as funções <code>concat()</code> e <code>merge()</code>; falta-nos agora a apresentação da última função, <code>join()</code>.</p>
<h2 id="heading-o-nome-ja-diz-a-funcao-join">O nome já diz: a função <code>join()</code></h2>
<p>Quando você vê o nome da função, <code>join()</code>, é possível que pense outra vez na cláusula <code>JOIN</code> do SQL. E a verdade é… que é por aí mesmo. Veja a tabela abaixo; a função do pandas nada mais é que uma “tradução” das funções de <code>JOIN</code> para uma forma a ser utilizada através de uma biblioteca Python.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>pandas join()</td><td>SQL JOIN</td><td>Operação</td></tr>
</thead>
<tbody>
<tr>
<td>how='inner'</td><td>INNER JOIN</td><td>Retorna apenas registros que correspondem em ambas as fontes</td></tr>
<tr>
<td>how='left'</td><td>LEFT JOIN</td><td>Retorna todos os registros da fonte esquerda + correspondências da direita</td></tr>
<tr>
<td>how='right'</td><td>RIGHT JOIN</td><td>Retorna todos os registros da fonte direita + correspondências da esquerda</td></tr>
<tr>
<td>how='outer'</td><td>FULL OUTER JOIN</td><td>Retorna todos os registros de ambas as fontes</td></tr>
</tbody>
</table>
</div><p>Agora, se você está conosco há algum tempo e se lembra das aulas anteriores, essas informações vão parecer um tanto familiares. E são familiares mesmo! Perceba que as características batem com uma outra função do pandas, <code>merge()</code>.</p>
<h3 id="heading-mas-e-tudo-igual-mesmo-comparando-join-com-merge">Mas é tudo igual <em>mesmo</em>? Comparando <code>join()</code> com <code>merge()</code></h3>
<p>É possível que você pense que a função <code>join()</code>seja uma mera redundância do <code>merge()</code>, e que a escolha de qual recurso utilizar é indiferente quando se quer fazer uma combinação de DataFrames. No entanto, as coisas não precisam ser (e não são, na verdade) assim. Dê uma olhada na tabela abaixo; aqui você verá duas coisas: apontamentos sobre as diferenças entre as funções do pandas e a equivalência com a cláusula do SQL.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Característica</td><td>pandas join()</td><td>pandas merge()</td><td>SQL JOIN</td></tr>
</thead>
<tbody>
<tr>
<td>Uso Principal</td><td>Combinar DataFrames baseado em índices</td><td>Combinar DataFrames baseado em colunas</td><td>Combinar tabelas baseado em colunas</td></tr>
<tr>
<td>Sintaxe Básica</td><td><code>df1.join(df2)</code></td><td><code>df1.merge(df2, on='coluna')</code></td><td><code>SELECT * FROM t1 JOIN t2 ON t1.col = t2.col</code></td></tr>
<tr>
<td>Base da Junção</td><td>Índices por padrão, pode usar colunas com <code>on</code></td><td>Colunas específicas usando <code>on</code>, <code>left_on</code>, <code>right_on</code></td><td>Colunas específicas usando cláusula <code>ON</code></td></tr>
<tr>
<td>Tipos de Join</td><td>- <code>how='left'</code><br />- <code>how='right'</code><br />- <code>how='inner'</code><br />- <code>how='outer'</code></td><td>- <code>how='left'</code><br />- <code>how='right'</code><br />- <code>how='inner'</code><br />- <code>how='outer'</code><br />- <code>how='cross'</code></td><td>- <code>LEFT JOIN</code><br />- <code>RIGHT JOIN</code><br />- <code>INNER JOIN</code><br />- <code>FULL OUTER JOIN</code><br />- <code>CROSS JOIN</code></td></tr>
<tr>
<td>Tratamento de Colunas Duplicadas</td><td>Usa <code>lsuffix</code> e <code>rsuffix</code></td><td>Usa <code>suffixes</code></td><td>Requer aliases explícitos na consulta</td></tr>
<tr>
<td>Melhor Para</td><td>- Junções simples baseadas em índice<br />- Dados já indexados corretamente<br />- Operações mais diretas</td><td>- Junções complexas<br />- Múltiplas colunas de junção<br />- Maior flexibilidade</td><td>- Junções complexas<br />- Múltiplas condições<br />- Operações em banco de dados</td></tr>
<tr>
<td>Limitações</td><td>- Menos flexível para junções complexas<br />- Primariamente focado em índices</td><td>- Sintaxe mais verbosa<br />- Pode ser complexo para junções simples</td><td>- Requer conhecimento de SQL<br />- Menos integrado com análise de dados em Python</td></tr>
<tr>
<td>Performance</td><td>Melhor para junções baseadas em índice</td><td>Melhor para junções complexas de DataFrames</td><td>Otimizado para operações em banco de dados</td></tr>
</tbody>
</table>
</div><p>Desta tabela, uma coisa fica clara: enquanto <code>merge()</code> dá a possibilidade de combinar DataFrames baseados em <em>colunas</em>, a concentração de <code>join()</code> se dá nos <em>índices</em> do DataFrame. Para lembrar o que são índices para o <a target="_blank" href="https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.index.html">pandas</a>:</p>
<blockquote>
<p>The index of a DataFrame is a series of labels that identify each row. The labels can be integers, strings, or any other hashable type. The index is used for label-based access and alignment, and can be accessed or modified using this attribute.</p>
</blockquote>
<p>Traduzindo, é algo assim:</p>
<blockquote>
<p>O índice de um DataFrame é uma série de etiquetas (labels) que identificam cada linha. Podem ser números inteiros, strings, ou qualquer tipo de dado que possa ser utilizada como chave. É utilizado para acesso e alinhamento de dados baseando-se em etiquetas, podendo acessar e modificar linhas usando esse mesmo atributo.</p>
</blockquote>
<p>Então, em vez de nos orientarmos pelos nomes das colunas, como em <code>merge()</code>, podemos nos valer de, digamos, os “nomes” das linhas usando o <code>join()</code>.</p>
<h3 id="heading-um-exemplo-pratico">Um exemplo prático</h3>
<p>Comecemos o exemplo criando dois DataFrames de características envolvendo aspectos corpóreos de um grupo limitado de aves. Nesse caso, como usaremos o <code>join()</code>, daremos uma atenção especial aos índices de cada DataFrame. Cada linha das tabelas possuirá um nome científico de uma ave em específico.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

<span class="hljs-comment"># Criando DataFrame com dados das asas</span>
df_asas = pd.DataFrame({
    <span class="hljs-string">'envergadura_cm'</span>: [<span class="hljs-number">240</span>, <span class="hljs-number">180</span>, <span class="hljs-number">85</span>, <span class="hljs-number">120</span>, <span class="hljs-number">300</span>],
    <span class="hljs-string">'comp_dedo_medio_cm'</span>: [<span class="hljs-number">12</span>, <span class="hljs-number">8</span>, <span class="hljs-number">4</span>, <span class="hljs-number">6</span>, <span class="hljs-number">15</span>],
    <span class="hljs-string">'comp_asa_cm'</span>: [<span class="hljs-number">110</span>, <span class="hljs-number">85</span>, <span class="hljs-number">40</span>, <span class="hljs-number">55</span>, <span class="hljs-number">145</span>]
}, index=[<span class="hljs-string">'Aquila chrysaetos'</span>,  <span class="hljs-comment"># Águia-real</span>
          <span class="hljs-string">'Buteo buteo'</span>,        <span class="hljs-comment"># Águia-de-asa-redonda</span>
          <span class="hljs-string">'Falco tinnunculus'</span>,  <span class="hljs-comment"># Peneireiro-vulgar</span>
          <span class="hljs-string">'Accipiter nisus'</span>,    <span class="hljs-comment"># Gavião-da-europa</span>
          <span class="hljs-string">'Gyps fulvus'</span>])       <span class="hljs-comment"># Grifo</span>

<span class="hljs-comment"># Criando DataFrame com dados das pernas</span>
df_pernas = pd.DataFrame({
    <span class="hljs-string">'comp_tarso_cm'</span>: [<span class="hljs-number">9.5</span>, <span class="hljs-number">7.2</span>, <span class="hljs-number">4.5</span>, <span class="hljs-number">5.8</span>, <span class="hljs-number">10.2</span>],
    <span class="hljs-string">'comp_total_perna_cm'</span>: [<span class="hljs-number">35</span>, <span class="hljs-number">28</span>, <span class="hljs-number">18</span>, <span class="hljs-number">22</span>, <span class="hljs-number">40</span>],
    <span class="hljs-string">'circunf_tarso_cm'</span>: [<span class="hljs-number">8</span>, <span class="hljs-number">6</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">9</span>]
}, index=[<span class="hljs-string">'Aquila chrysaetos'</span>,    <span class="hljs-comment"># Águia-real</span>
          <span class="hljs-string">'Buteo buteo'</span>,          <span class="hljs-comment"># Águia-de-asa-redonda</span>
          <span class="hljs-string">'Falco tinnunculus'</span>,    <span class="hljs-comment"># Peneireiro-vulgar</span>
          <span class="hljs-string">'Strix aluco'</span>,          <span class="hljs-comment"># Coruja-do-mato</span>
          <span class="hljs-string">'Gyps fulvus'</span>])         <span class="hljs-comment"># Grifo</span>
</code></pre>
<p>Perceba já de início que existem alguns índices que possuem nomes iguais (que é o intuito dessa atividade); esta parte é muito importante para usar o <code>join()</code>. A partir daqui, então, já podemos “traduzir” as cláusulas do SQL para argumentos da função, assim como fizemos com o <code>merge()</code> anteriormente, como no bloco de código abaixo:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Exemplo 1: Inner join (apenas espécies que aparecem em ambos os DataFrames)</span>
df_inner = df_asas.join(df_pernas, how=<span class="hljs-string">'inner'</span>)

<span class="hljs-comment"># Exemplo 2: Left join (todas as espécies do DataFrame de asas)</span>
df_left = df_asas.join(df_pernas, how=<span class="hljs-string">'left'</span>)

<span class="hljs-comment"># Exemplo 3: Right join (todas as espécies do DataFrame de pernas)</span>
df_right = df_asas.join(df_pernas, how=<span class="hljs-string">'right'</span>)

<span class="hljs-comment"># Exemplo 4: Outer join (todas as espécies de ambos os DataFrames)</span>
df_outer = df_asas.join(df_pernas, how=<span class="hljs-string">'outer'</span>)
</code></pre>
<p>Como resultado, teremos para cada variável criada um DataFrame com os dados de asas e pernas de aves conforme o tipo de <code>JOIN</code> selecionado. Note que existem espécies que ocorrem em apenas uma das tabelas. Isso não vem a atrapalhar a mescla como um todo, mas é importante salientar que, no caso das colunas referentes ao outro DataFrame (onde a espécie não está descrita), os dados virão nulos.</p>
<h2 id="heading-o-resumo-da-opera">O resumo da ópera</h2>
<p>Chegando ao final das discussões sobre as diferentes formas de mesclar DataFrames usando pandas, podemos resumir tudo em uma tabela como esta abaixo, estabelecendo também comparações com a cláusula JOIN do SQL:</p>
<h1 id="heading-comparacao-entre-metodos-de-juncao-pandas-e-sql">Comparação entre métodos de junção pandas e SQL</h1>
<h1 id="heading-comparacao-entre-metodos-de-juncao-pandas-e-sql-1">Comparação entre métodos de junção pandas e SQL</h1>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Característica</td><td>pandas join()</td><td>pandas merge()</td><td>pandas concat()</td><td>SQL JOIN</td></tr>
</thead>
<tbody>
<tr>
<td>Uso Principal</td><td>Combinar DataFrames baseado em índices</td><td>Combinar DataFrames baseado em colunas</td><td>Empilhar DataFrames (vertical ou horizontal)</td><td>Combinar tabelas baseado em colunas</td></tr>
<tr>
<td>Sintaxe Básica</td><td><code>df1.join(df2)</code></td><td><code>df1.merge(df2, on='coluna')</code></td><td><code>pd.concat([df1, df2])</code></td><td><code>SELECT * FROM t1 JOIN t2 ON t1.col = t2.col</code></td></tr>
<tr>
<td>Base da Junção</td><td>Índices por padrão, pode usar colunas com <code>on</code></td><td>Colunas específicas usando <code>on</code>, <code>left_on</code>, <code>right_on</code></td><td>Posição (eixo) dos DataFrames</td><td>Colunas específicas usando cláusula <code>ON</code></td></tr>
<tr>
<td>Tipos de Operação</td><td>- <code>how='left'</code><br />- <code>how='right'</code><br />- <code>how='inner'</code><br />- <code>how='outer'</code></td><td>- <code>how='left'</code><br />- <code>how='right'</code><br />- <code>how='inner'</code><br />- <code>how='outer'</code><br />- <code>how='cross'</code></td><td>- <code>axis=0</code> (vertical)<br />- <code>axis=1</code> (horizontal)<br />- <code>join='outer'</code><br />- <code>join='inner'</code></td><td>- <code>LEFT JOIN</code><br />- <code>RIGHT JOIN</code><br />- <code>INNER JOIN</code><br />- <code>FULL OUTER JOIN</code><br />- <code>CROSS JOIN</code></td></tr>
<tr>
<td>Tratamento de Duplicatas</td><td>Usa <code>lsuffix</code> e <code>rsuffix</code></td><td>Usa <code>suffixes</code></td><td>Usa <code>ignore_index</code> e <code>keys</code></td><td>Requer aliases explícitos na consulta</td></tr>
<tr>
<td>Melhor Para</td><td>- Junções simples baseadas em índice<br />- Dados já indexados corretamente<br />- Operações mais diretas</td><td>- Junções complexas<br />- Múltiplas colunas de junção<br />- Maior flexibilidade</td><td>- Combinar DataFrames sequencialmente<br />- Empilhar dados vertical/horizontalmente<br />- Manter índices originais</td><td>- Junções complexas<br />- Múltiplas condições<br />- Operações em banco de dados</td></tr>
<tr>
<td>Limitações</td><td>- Menos flexível para junções complexas<br />- Primariamente focado em índices</td><td>- Sintaxe mais verbosa<br />- Pode ser complexo para junções simples</td><td>- Não faz junção baseada em valores<br />- Limitado a operações de empilhamento</td><td>- Requer conhecimento de SQL<br />- Menos integrado com análise em Python</td></tr>
<tr>
<td>Performance</td><td>Melhor para junções baseadas em índice</td><td>Melhor para junções complexas de DataFrames</td><td>Eficiente para empilhamento simples</td><td>Otimizado para operações em banco de dados</td></tr>
<tr>
<td>Exemplo de Uso Comum</td><td>Combinar dados financeiros usando datas como índice</td><td>Combinar dados de vendas usando ID do cliente</td><td>Combinar relatórios mensais sequencialmente</td><td>Combinar dados de diferentes tabelas relacionais</td></tr>
</tbody>
</table>
</div><hr />
<p>Esta é, portanto, a última aula que explora as três funções que podemos usar para juntar tabelas usando o pandas: <code>concat()</code>, <code>join()</code>, e <code>merge()</code>. Continuaremos a explorar outros atributos do pandas e do Python para analisar dados, especialmente os dados ecológicos, nas próximas aulas a serem publicadas em breve.</p>
<p>Aproveite o conteúdo para seguir estudando! Um abraço e até a próxima!</p>
<hr />
<p><strong>Para ler mais:</strong></p>
<ul>
<li><p><a target="_blank" href="https://hub.asimov.academy/tutorial/join-no-pandas-como-utilizar-o-metodo-join-de-dataframes/">Join no Pandas - Asimov Academy</a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/22676081/what-is-the-difference-between-join-and-merge-in-pandas">What is the difference between join and merge in Pandas? - Stack Overflow</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Aula 10.2 - Análise e visualização de dados em Python - biblioteca pandas (parte 7)]]></title><description><![CDATA[Na última aula, nós vimos as possibilidades de juntar conjuntos de dados em um só usando a função concat() do pandas. Agora, e se quisermos juntar os nossos dados de uma maneira que a concatenação não consegue cobrir?
O pandas, como vimos até então, ...]]></description><link>https://blog.matheusyuri.pro/aula-102-analise-e-visualizacao-de-dados-em-python-biblioteca-pandas-parte-7</link><guid isPermaLink="true">https://blog.matheusyuri.pro/aula-102-analise-e-visualizacao-de-dados-em-python-biblioteca-pandas-parte-7</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[pandas]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[Databases]]></category><category><![CDATA[data structures]]></category><category><![CDATA[#ecology]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Wed, 01 Jan 2025 11:13:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1714319838402/fa68f086-26d5-4753-a3f2-8b7cbc9d069e.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Na última aula, nós vimos as possibilidades de juntar conjuntos de dados em um só usando a função <code>concat()</code> do pandas. Agora, e se quisermos juntar os nossos dados de uma maneira que a concatenação não consegue cobrir?</p>
<p>O pandas, como vimos até então, é uma espécie de 'canivete suíço' para quem quer analisar seus dados; muito por isso, a biblioteca nos oferece mais funções para que possamos 'aliviar a dor' de juntar conjuntos de dados que temos em mãos. Nesta aula, a função da vez é a <code>merge()</code>.</p>
<h2 id="heading-junte-se-a-nos-mas-de-que-jeito-funcao-merge">Junte-se a nós... mas de que jeito?: função <code>merge()</code></h2>
<p>Ainda mencionando a função <code>concat()</code>, vimos que ela funciona de maneira que se consiga <em>empilhar</em> dois ou mais DataFrames, seja um em cima do outro, seja um do lado do outro. Isso funciona bem para dados que possuam colunas exatamente iguais, ou até mesmo índices... mas e se não for o seu caso?</p>
<p>Se você conhece um pouco de <a target="_blank" href="[https://pt.wikipedia.org/wiki/SQL](https://pt.wikipedia.org/wiki/SQL)">SQL</a>, é capaz de se lembrar de uma cláusula chamada <code>JOIN</code>. Como o próprio nome diz, é uma cláusula destinada a <em>juntar</em> dois conjutos de dados, num primeiro momento, em apenas um, podendo considerar diferentes aspectos para gerar o resultado esperado.</p>
<p>A função <code>merge()</code> do pandas, em bom português, possui poder semelhante ao <code>JOIN</code>; logo, você pode lançar mão dessa função para juntar DataFrames. <strong>Mas cuidado:</strong> assim como foi dito muitas vezes no universo de Homem-Aranha, <strong>"com grandes poderes vêm grandes responsabilidades"</strong>. A pergunta que fica depois disso é: quais são as "responsabilidades" do <code>merge()</code>?</p>
<h3 id="heading-como-juntar-o-parametro-how">Como juntar? O parâmetro <code>how</code></h3>
<p>Caso voltemos nossos olhos à documentação do pandas, especialmente no que toca à função <code>merge()</code>, percebemos a presença de um grande número de parâmetros, onde você pode fazer várias modificações a fim de performar uma "sintonia fina", para chegar ao resultado que se espera. No entanto, demos foco primeiramente a um dos mais importantes: o parâmetro <code>how</code>.</p>
<p>Pensemos primeiro na cláusula <code>JOIN</code> do SQL: esta se desdobra em métodos específicos de mescla, como <code>OUTER JOIN</code>, <code>INNER JOIN</code>, e assim por diante. A mesma coisa pode ser vista na função <code>merge()</code>, através do argumento <code>how</code>; a diferença estará na sintaxe, basicamente. </p>
<p>Observe a tabela e a imagem abaixo, onde estão as diferenças de sintaxe entre o pandas e o SQL, e quais são as possibilidades de usar cada função e cláusula. Perceba que os nomes já indicam que tipo de operação será feita; mas, ainda assim, veremos com um pouco mais de detalhe cada uma delas mais à frente.</p>





  <table>
    <thead>
      <tr>
        <th>pandas merge()</th>
        <th>SQL JOIN</th>
        <th>Operação</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><span class="code">how='inner'</span></td>
        <td><span class="code">INNER JOIN</span></td>
        <td>Retorna apenas registros que correspondem em ambas as fontes</td>
      </tr>
      <tr>
        <td><span class="code">how='left'</span></td>
        <td><span class="code">LEFT JOIN</span></td>
        <td>Retorna todos os registros da fonte esquerda + correspondências da direita</td>
      </tr>
      <tr>
        <td><span class="code">how='right'</span></td>
        <td><span class="code">RIGHT JOIN</span></td>
        <td>Retorna todos os registros da fonte direita + correspondências da esquerda</td>
      </tr>
      <tr>
        <td><span class="code">how='outer'</span></td>
        <td><span class="code">FULL OUTER JOIN</span></td>
        <td>Retorna todos os registros de ambas as fontes</td>
      </tr>
    </tbody>
  </table>



<p><img src="https://mermaid.ink/img/pako:eNp1ksFOGzEQhl9l5EtASlrRclqpHFASGpSGiC6XZhGarmezFrv2dmwDVciVB-AR-ip9kz4JXqftbqH4NLa_-e3_12xEbiSJRBSVuc1LZAfpONMQlvVf14xNCUvUEu0qE00s3tTEa9rbz8TlDmyXVEy5U0ZDetydLg9WY3Q4ZawJJvabJ5bmEkajI7iPKvewfNdDxkFFOdPTXb5fhYd7e-SfP2pybCw0rHSuGlQ26YARlOY2gc2gosINhjBgtS5jobQmbgvjXSi2_R6jE8hN5TXu2X0IOdxQ_7rVujL6bdS66mAbfBfEpB3ZPm99Uag7sklbqbv2r8jYNfmmUjmGLLumkGbf9uG_tlPVBBFJEFN7bvfDb2_w6-ERZovF5BxOz2aLF1SMJELzyTT9P7OLK0Lns5OPr1C7CCM1vZjP4ewiffFo54i0zHSmxVCE79eoZJi3TXuVCVdSTZlIQimRr1vP28Chd-bzd52LxLGnoWDj16VICqxs2PlGoqOxwjCf9R8kDOcXY-q_EMkwSfxpN91xyLdPPtLm3w?type=png" alt /></p>
<h4 id="heading-quem-esta-dentro-quem-esta-fora-inner-e-outer">Quem está dentro, quem está fora: <code>inner</code> e <code>outer</code></h4>
<p>Examinemos com um pouco mais de detalhe as operações <code>inner</code> e <code>outer</code>. Para estabelecer comparações com as outras operações, estas duas primeiras consideram as duas fontes, ou tabelas, <em>na sua totalidade</em>. Isso quer dizer que, no momento da atuação do pandas, este dará o mesmo foco para quaisquer dados que apareçam para o mesmo juntar. Aqui, a diferença estará no que sairá de resultado.</p>
<p>A operação <code>outer</code> é, digamos, a mais simples dentre as que estamos analisando. Isso porque a única coisa que o pandas faz é juntar aquilo que aparece nas duas fontes igualmente, e incluir aquilo que aparece ou em uma, ou em outra fonte.</p>
<pre><code class="lang-python">df = pd.merge(df1, df2, how=<span class="hljs-string">'outer'</span>)
</code></pre>
<p>A operação <code>inner</code>, por sua vez, é marcada pelo fato de haver a separação de apenas aquilo que aparece nas duas tabelas/fontes que estamos analisando; ou seja, o que é comum entre os dois conjuntos de dados. O que é único dentro de cada conjunto fica fora do resultado.</p>
<pre><code class="lang-python">df = pd.merge(df1, df2, how=<span class="hljs-string">'inner'</span>)
</code></pre>
<h4 id="heading-considerando-um-ou-outro-left-e-right">Considerando um ou outro: <code>left</code> e <code>right</code></h4>
<p>Podemos dizer que as operações <code>left</code> e <code>right</code>, diferente das duas anteriores, estabelecem um foco especial em apenas uma das duas fontes, por vez. E isso se dá a partir da <em>posição</em> das tabelas no código que escrevemos. "Como assim?", você deve estar se perguntando. Explico:</p>
<ul>
<li>Assim como nas línguas portuguesa, inglesa, e tantas outras, o sentido de leitura de um código Python se dá da <em>esquerda</em> para a <em>direita</em>. Imagine uma operação matemática simples:<pre><code class="lang-python"><span class="hljs-number">5</span> + <span class="hljs-number">2</span> + <span class="hljs-number">3</span> + <span class="hljs-number">12</span>
</code></pre>
Intuitivamente, quando usamos a calculadora, ou fazemos o cálculo à mão, ou usamos a nossa imaginação para tanto, ordenamos os números da esquerda para a direita: Pegamos primeiro o <code>5</code>, somamos com o <code>2</code>, e assim por diante, até chegarmos ao resultado.<pre><code class="lang-python"><span class="hljs-number">22</span>
</code></pre>
</li>
<li>Com as fontes que usaremos para a mescla, é basicamente a mesma coisa. Observe a seguinte linha de código:<pre><code class="lang-python">pd.merge(df1, df2, how=<span class="hljs-string">'left'</span>, on=<span class="hljs-string">'ID'</span>)
</code></pre>
Por ser a primeira a aparecer na ordem de leitura, a fonte <code>df1</code> assumirá a posição da <em>esquerda</em>, enquanto <code>df2</code> assume a posição da <em>direita</em>.</li>
</ul>
<p>A partir disso, a diferença entre <code>left</code> e <code>right</code> como operações do parâmetro <code>how</code> fica bem mais clara. Ao utilizarmos o primeiro, damos foco à fonte de dados da <em>esquerda</em>, adquirindo da outra fonte à direita apenas o que é semelhante a ambos. Já o <code>right</code> tem como foco a tabela da direita, operando da mesma forma. </p>
<h3 id="heading-cade-a-chave-o-parametro-on">Cadê a chave? O parâmetro <code>on</code></h3>
<p>Até aqui, foi possível entender de que forma a função <code>merge()</code> funciona no que se refere a de que jeito vamos mesclar os conjuntos de dados que temos, de acordo com o foco que o pandas dará em relação às tabelas e suas posições. Tendo esse conhecimento adquirido, já é possível lançar mão da função para fazer mesclas. </p>
<p>Entretanto, em muitos casos, a indicação das posições por si só não fará com que alcancemos o resultado que estamos esperando, uma vez que, caso tenhamos uma ou mais colunas em comum para os dois conjuntos de dados, uma mescla 'pura' pode gerar duplicidades, alteração em colunas que possuem nomes iguais... em suma, isso vem gerar uma confusão que nos dará mais trabalho depois. Mas, na própria função <code>merge()</code>, há uma solução simples: apontar as <em>chaves</em> de cada tabela, a partir do parâmetro <code>on</code>.</p>
<p>Voltando ao SQL e adicionando um pouco de conceitos básicos de banco de dados, sabemos que, em um conjunto de dados dentro de um banco é possível ter o que chamamos de chaves; estas nada mais são do que valores únicos pelos quais podemos identificar dados dentro de uma tabela. </p>
<p>Para entender melhor, imaginemos o seguinte: Temos em mãos dois DataFrames com dados envolvendo características corpóreas de certas espécies de mamíferos, conforme o bloco de código a seguir:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

<span class="hljs-comment"># Criando o primeiro DataFrame com características físicas principais</span>
df1 = pd.DataFrame({
    <span class="hljs-string">'Especie'</span>: [<span class="hljs-string">'Leão'</span>, <span class="hljs-string">'Tigre'</span>, <span class="hljs-string">'Urso Pardo'</span>, <span class="hljs-string">'Lobo Cinzento'</span>, <span class="hljs-string">'Jaguar'</span>],
    <span class="hljs-string">'comprimento_cm'</span>: [<span class="hljs-number">250</span>, <span class="hljs-number">300</span>, <span class="hljs-number">200</span>, <span class="hljs-number">150</span>, <span class="hljs-number">180</span>],
    <span class="hljs-string">'tamanho_pes_cm'</span>: [<span class="hljs-number">18</span>, <span class="hljs-number">20</span>, <span class="hljs-number">25</span>, <span class="hljs-number">15</span>, <span class="hljs-number">16</span>],
    <span class="hljs-string">'tamanho_presas_cm'</span>: [<span class="hljs-number">8</span>, <span class="hljs-number">7.5</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>]
})

<span class="hljs-comment"># Criando o segundo DataFrame com características faciais</span>
df2 = pd.DataFrame({
    <span class="hljs-string">'Especie'</span>: [<span class="hljs-string">'Leão'</span>, <span class="hljs-string">'Tigre'</span>, <span class="hljs-string">'Urso Pardo'</span>, <span class="hljs-string">'Lobo Cinzento'</span>, <span class="hljs-string">'Onça Pintada'</span>],
    <span class="hljs-string">'tamanho_garras_cm'</span>: [<span class="hljs-number">6</span>, <span class="hljs-number">8</span>, <span class="hljs-number">10</span>, <span class="hljs-number">4</span>, <span class="hljs-number">7</span>],
    <span class="hljs-string">'tamanho_focinho_cm'</span>: [<span class="hljs-number">20</span>, <span class="hljs-number">22</span>, <span class="hljs-number">35</span>, <span class="hljs-number">25</span>, <span class="hljs-number">18</span>]
})
</code></pre>
<p>Aqui, já de início, podemos perceber uma coisa: a existência de uma coluna com nome e valores em comum. Esta coluna, <code>Especie</code>, vem a servir de identificador dos DataFrames, uma vez que possui valores que, em princípio, não se repetem na tabela. Desse modo, podemos encarar essa coluna como a <em>chave</em> dos DataFrames que foram criados.</p>
<p>Seguindo a ideia dessa aula, imaginemos a situação de mesclar os dois DataFrames que criamos, com o intuito de juntar todas as características corpóreas de cada espécie registrada nesses dois conjuntos de dados. É perfeitamente possível se valer da função <code>merge()</code> indicando apenas os dois <code>df</code>, conforme exemplo abaixo:</p>
<pre><code class="lang-python">df3 = pd.merge(df1, df2, how=<span class="hljs-string">'outer'</span>)
</code></pre>
<p>Existe aí, no entanto, um porém: Ao executarmos esse código, e verificarmos seu resultado, é possível encontrar a coluna <code>Especie</code> repetida, com indicadores atrelados ao nome (algo como <code>Especie_x</code> e <code>Especie_y</code>). Isso, querendo nós ou não, atrapalha muito na hora de fazer quaisquer análises. E o que faremos com isso, então?</p>
<p>Nesse blog, procuramos sempre preconizar o princípio de que existirá uma solução efetiva para os problemas que encontramos na análise de dados usando Python; aqui não será diferente. Para resolvermos essa questão de uma vez por todas, basta complementarmos a linha de código anterior fazendo menção à coluna que as tabelas possuem em comum usando o parâmetro <code>on</code>, conforme exemplo:</p>
<pre><code class="lang-python">df3 = pd.merge(df1, df2, how=<span class="hljs-string">'outer'</span>, on=<span class="hljs-string">'Especie'</span>)
</code></pre>
<p>Adicionando valor a esse parâmetro, indicaremos ao pandas que, uma vez encontrado um valor comum de <code>Especie</code> em ambos os conjuntos de dados, a única coisa que é preciso fazer é uma complementação dos dados que já existem, adicionando novas colunas e os valores atrelados a elas. Assim teremos um DataFrame único em <code>df3</code>, sem colunas repetidas, e com todos os dados disponíveis nas duas tabelas, prontas para que possamos tomar quaisquer outras ações posteriores.</p>
<hr />
<p>Vimos até aqui duas formas muito interessantes de combinar dados oriundos de fontes distintas, <code>concat()</code> e <code>merge()</code>. Com elas, sem a menor sombra de dúvida, você já estará pronto para organizar os vários fragmentos de dados que acaso poderá encontrar ao lidar com arquivos do mundo real. Ainda nos falta discutir um pouco sobre uma outra função que também serve para combinações e mesclas, o <code>join()</code>. Isso faremos em uma próxima oportunidade, de forma mais detalhada e clara.</p>
<p>Um grande abraço, e até o próximo post!</p>
<hr />
<p><strong>Para ler mais:</strong></p>
<ul>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/53645882/pandas-merging-101"><strong>Pandas Merging 101 - StackOverflow</strong></a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/49620538/what-are-the-levels-keys-and-names-arguments-for-in-pandas-concat-functio/49620539#49620539"><strong>What are the 'levels', 'keys', and names arguments for in Pandas' concat function? - Stack Overflow</strong></a></p>
</li>
<li><p><a target="_blank" href="https://towardsdatascience.com/python-pandas-dataframe-join-merge-and-concatenate-84985c29ef78"><strong>Python Pandas DataFrame Join, Merge, and Concatenate - Towards Data Science</strong></a></p>
</li>
<li><p><a target="_blank" href="https://towardsdatascience.com/practical-uses-of-merge-join-and-concat-8f011bbac241"><strong>Practical uses of merge, join and concat - Towards Data Science</strong></a></p>
</li>
<li><p><a target="_blank" href="https://realpython.com/pandas-merge-join-and-concat/"><strong>Combining Data in pandas With merge(), .join(), and concat() - Real Python</strong></a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Unlocking the Power of JSON in Clinical Data Management: A Practical Guide]]></title><description><![CDATA[Context
In clinical studies, we often work with datasets that can come in various formats, depending on what the chosen EDC system can offer. However, in some situations, it will be necessary to extract a complete dataset according to what regulatory...]]></description><link>https://blog.matheusyuri.pro/unlocking-the-power-of-json-in-clinical-data-management-a-practical-guide</link><guid isPermaLink="true">https://blog.matheusyuri.pro/unlocking-the-power-of-json-in-clinical-data-management-a-practical-guide</guid><category><![CDATA[json]]></category><category><![CDATA[CDISC]]></category><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[Databases]]></category><category><![CDATA[data structures]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Tue, 19 Nov 2024 19:41:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732044992833/d6fada63-d0f2-4656-acc6-73f19ffef757.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-context">Context</h1>
<p>In clinical studies, we often work with datasets that can come in various formats, depending on what the chosen <a target="_blank" href="https://en.wikipedia.org/wiki/Electronic_data_capture">EDC</a> system can offer. However, in some situations, it will be necessary to extract a complete dataset according to what regulatory entities require for the approval submissions of drug and vaccine use, mainly. Among the formats that frequently appear as options are XML <a target="_blank" href="https://hashnode.com/post/clzjxe1zi000f09l44nqga8ip">(which we have seen previously)</a>, and JSON. To ease the anxiety that sometimes arises when facing these "monsters," today we'll see in practice how to handle a JSON file.</p>
<h1 id="heading-what-is-json">What is JSON?</h1>
<p><strong>JSON</strong> stands for <em>JavaScript Object Notation</em>, a data representation that, like <strong>XML</strong>, can be used for data transmission. As the name suggests, it is based on a subset of the JavaScript language; however, it has a universal structure that can be read and manipulated by various programming languages <a class="post-section-overview" href="#one"><sup>1</sup></a>.</p>
<h2 id="heading-dataset-json">Dataset-JSON</h2>
<p><strong>Dataset-JSON</strong> is an <a target="_blank" href="https://www.cdisc.org/dataset-json">ongoing initiative</a> led by CDISC and PHUSE <a class="post-section-overview" href="#two"><sup>2</sup></a>, aiming to establish a lighter, faster, and more human-readable alternative to the current clinical data transfer models (namely, SAS and Dataset-XML, the latter already discussed on the blog).</p>
<h2 id="heading-differences-between-json-and-xml-for-data-storage-and-transfer">Differences between JSON and XML for Data Storage and Transfer</h2>
<p>Especially in the case of clinical study data, various sources indicate that the JSON format has certain advantages over the XML format. We can list a few here:</p>
<ul>
<li><p><strong>XML</strong>, although an improvement over older clinical data models, is still a large file format, mainly due to its verbose nature. In a single tag, for example, there can be more than one attribute representing important information (this issue was discussed in the second post about XML on the blog). <strong>JSON</strong> has a simpler and more flexible structure, capable of storing the same amount of information as XML in a smaller, easier-to-read file, saving memory and energy.</p>
</li>
<li><p><strong>JSON</strong> is fully compatible with APIs and can be seen in newer versions of EDCs (such as OpenClinica from version v. 4.x, and the latest versions of REDCap Academic and Cloud), making data transmission easier without the need to manually download files <a class="post-section-overview" href="#three"><sup>3</sup></a>. XML, although present in some APIs, does not have the same presence and ease as JSON.</p>
</li>
<li><p><strong>JSON</strong> contains basic information about the variables within its own file. For XML, although this is possible (as we have seen in previous posts), it is not necessarily the rule and often depends on external files <a class="post-section-overview" href="#four"><sup>4</sup></a>.</p>
</li>
<li><p><strong>XML</strong> allows the addition of new <em>namespaces</em>, metadata, and other information, but its rigid structure is a critical limiting factor for this. JSON is much more flexible, with a simpler and more user-friendly structure for adding new data.</p>
</li>
</ul>
<p>Let's look at examples of how the elements that make up XML and JSON files are distributed in memory when read. The first case is a tree similar to the ODM tree schema of XML files we have seen before. The XML tree has a high degree of complexity, as shown in the diagram below, with many elements needing to be stored in their own memory spaces. This requires more "jumps" between elements to reach the desired data.</p>
<p><img src="https://mermaid.ink/img/pako:eNptkbFOAzEMQH8l8twOlO2QkGhzLQxdKBMXBvfi3kW6JKfUGVDVr-IT-DHSnKCRiif7PVuW7BO0XhNU0AUce_EmH5QTKY5xP5Et2e-vYHDCl3hqXr3njwKI-fxRLJt6IEuO727U6lctCrXMSja7uP9ncJVtXdjFjV0X9r6wdbabRiJjgdcZP09YXLnM_KVsJ6dhBpaCRaPTcU4XrID7tEtBlVJHkQMOCpQ7p1aM7HefroWKQ6QZBB-7HqoDDsdUxVEjkzSYTmr_6Iju3ftrTdqwD9vpHa13B9PB-QfXMnlv?type=png" alt="&quot;Esquema de distribuição dos elementos de um arquivo XML na memória.&quot;" class="image--center mx-auto" /></p>
<p>When we talk about the tree of a JSON file, you can immediately notice a reduction in complexity: the data is with the sub-elements, which means it takes up less space in memory and requires fewer "jumps" here, saving time and energy. The diagram is below.</p>
<p><img src="https://mermaid.ink/img/pako:eNplkDEOwjAMRa8SeaYDsAUJCWjZWCgTDYMhhlZqkio4A0KciiNwMUIroAhP9v9PtvyvcHCaQMLJY1OKTTpRVsQ6h32nrMg87r7CTn7VrFg7xzuRJFMxL7KaDFke7iZfYt56iyIP-7ctRYqM_1Dag0b_0KyFsveVUd_LWm_ZWzD-XUBWwwAMeYOVji9eX7ICLiOsQMbWUmCPtQJlbxHFwC6_2ANI9oEG4F04lSCPWJ_jFBqNTGmFMRjzURu0W-e-M-mKnV91obbZ3p5B5Wzq?type=png" alt="Esquema de distribuição dos elementos de um arquivo JSON na memória." class="image--center mx-auto" /></p>
<p>From here, we can provide a summary of this comparison:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Aspect</strong></td><td><strong>Dataset-XML</strong></td><td><strong>Dataset-JSON</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Structure</strong></td><td>Hierarchical tree with pointers to parents/children</td><td>Objects nested without explicit pointers</td></tr>
<tr>
<td><strong>Memory usage</strong></td><td>High (4-5x larger than the original file)</td><td>Low (closer to the original size)</td></tr>
<tr>
<td><strong>Complexity</strong></td><td>High (necessary to maintain relationships between nodes)</td><td>Low (flat structure with arrays and dictionaries)</td></tr>
<tr>
<td><strong>Efficiency</strong></td><td>Less efficient in terms of access</td><td>More efficient due to the simplicity of the structure</td></tr>
</tbody>
</table>
</div><h1 id="heading-using-python-to-handle-json">Using Python to handle JSON</h1>
<h2 id="heading-data-to-be-used">Data to be Used</h2>
<p>The data we will use in this article is still from the CDISC repository on GitHub, but it is in a separate folder dedicated to Dataset-JSON files. Besides the example that will be our focus here, there are many other datasets available that can be viewed, extracted, and manipulated.</p>
<h2 id="heading-libraries-to-be-imported">Libraries to be Imported</h2>
<p>When using Python to handle data from JSON files, we will use a specific library dedicated to this type of document: <code>json</code>. This is a native Python library, so if you are using WinPython or Anaconda, you can likely access the tool with just an import. The other libraries to be imported are ones we are already familiar with: <code>requests</code> and <code>pandas</code>.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests, json
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
</code></pre>
<h2 id="heading-acquiring-and-exploring-the-data">Acquiring and Exploring the Data</h2>
<p>To get the data we will analyze, you can follow similar steps to those we've seen in previous posts using the <code>requests</code> library. With the <code>requests.get()</code> function, we send a request to GitHub to obtain the JSON file we want, and once this request is successful, we can store its content in a variable, <code>example</code>.</p>
<p>As mentioned before, unlike what we do with XML files, we will use the <code>json</code> package to read the file resulting from the request. For this case, we use the <code>json.loads()</code> function, as shown below.</p>
<pre><code class="lang-python">example = requests.get(<span class="hljs-string">'https://github.com/cdisc-org/DataExchange-DatasetJson/raw/refs/heads/master/examples/i18n/ae.json'</span>)
example = example.content
example = json.loads(example)
</code></pre>
<p>The result of this "loading" <a target="_blank" href="https://www.boardinfinity.com/blog/dict-to-json-in-python/">is an object similar to Python's <code>dict</code></a>, a dictionary <a class="post-section-overview" href="#five"><sup>5</sup></a> <a class="post-section-overview" href="#six"><sup>6</sup></a>; this is one of the types proposed for JSON when it is read by some software or language package. In this dictionary, we will find all the information we need to identify the data and put it into a readable and explorable DataFrame.</p>
<p>If we explore this dictionary in an IDE like <a target="_blank" href="https://www.spyder-ide.org/">Spyder</a>, which is available in both WinPython and Anaconda, we will see a classic key-value structure of a dictionary, but we will also see other things that interest us here, as shown in the image below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731986675802/9794680b-cc39-4608-bddc-2cc7f38e6d5e.png" alt class="image--center mx-auto" /></p>
<p>From the metadata version to the number of records contained in the JSON file, there are several essential pieces of information in the file. However, let's focus on just two keys: <code>columns</code> and <code>rows</code>. These values will be used to build the pandas DataFrame that we can explore later.</p>
<h2 id="heading-accessing-data-within-the-json">Accessing Data Within the JSON</h2>
<p>To access the data in <code>rows</code> and <code>columns</code> within the <code>example</code> object, we just need to follow the logic of a Python dictionary, as mentioned earlier. By using the method <code>object[key]</code>, or <code>objeto[chave]</code>, we can access the data we want within the <code>example</code> dictionary, using something like the block below:</p>
<pre><code class="lang-python">columns = example[<span class="hljs-string">'columns'</span>]
rows = example[<span class="hljs-string">'rows'</span>]
</code></pre>
<p>With this, we can have full access to the content we will use to build the DataFrame. If we call the <code>columns</code> object in the console, we will be able to see all the content it contains.</p>
<pre><code class="lang-python">columns
</code></pre>
<pre><code class="lang-python">[{<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.STUDYID'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'STUDYID'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Study Identifier'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">12</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.DOMAIN'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'DOMAIN'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Domain Abbreviation'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">2</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.USUBJID'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'USUBJID'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Unique Subject Identifier'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">11</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESEQ'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESEQ'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Sequence Number'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESPID'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESPID'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Sponsor-Defined Identifier'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">3</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AETERM'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AETERM'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Reported Term for the Adverse Event'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">200</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AELLT'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AELLT'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Lowest Level Term'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">100</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AELLTCD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AELLTCD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Lowest Level Term Code'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEDECOD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEDECOD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Dictionary-Derived Term'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">200</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEPTCD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEPTCD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Preferred Term Code'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEHLT'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEHLT'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'High Level Term'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">100</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEHLTCD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEHLTCD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'High Level Term Code'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEHLGT'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEHLGT'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'High Level Group Term'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">100</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEHLGTCD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEHLGTCD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'High Level Group Term Code'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEBODSYS'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEBODSYS'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Body System or Organ Class'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">67</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEBDSYCD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEBDSYCD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Body System or Organ Class Code'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESOC'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESOC'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Primary System Organ Class'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">100</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESOCCD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESOCCD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Primary System Organ Class Code'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESEV'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESEV'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Severity/Intensity'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">8</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESER'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESER'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Serious Event'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEACN'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEACN'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Action Taken with Study Treatment'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">30</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEREL'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEREL'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Causality'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">8</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEOUT'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEOUT'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Outcome of Adverse Event'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">200</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESCAN'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESCAN'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Involves Cancer'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESCONG'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESCONG'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Congenital Anomaly or Birth Defect'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESDISAB'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESDISAB'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Persist or Signif Disability/Incapacity'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESDTH'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESDTH'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Results in Death'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESHOSP'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESHOSP'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Requires or Prolongs Hospitalization'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESLIFE'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESLIFE'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Is Life Threatening'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESOD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESOD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Occurred with Overdose'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEDTC'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEDTC'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Date/Time of Collection'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">10</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESTDTC'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESTDTC'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Start Date/Time of Adverse Event'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">10</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEENDTC'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEENDTC'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'End Date/Time of Adverse Event'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">10</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESTDY'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESTDY'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Study Day of Start of Adverse Event'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEENDY'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEENDY'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Study Day of End of Adverse Event'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AETRTEM'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AETRTEM'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'TREATMENT EMERGENT FLAG'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>}]
</code></pre>
<p>Notice that when we access <code>columns</code>, we not only have the column name but also what it means (through the <code>label</code>), the data type (through the <code>dataType</code>), and the OID, which is the object identifier <a class="post-section-overview" href="#seven"><sup>7</sup></a>. This highlights the ease with which JSON can handle and access file metadata, an advantage over XML, which, although it allows metadata access in the same file, does not do so as easily.</p>
<p>Moving forward, to see what the <code>rows</code> object contains, we use the same method as before. Since it is expected that the number of records is large (when we check the <code>records</code> key in the dictionary, we have 1191 records!), we will only look at the first occurrence in this case.</p>
<pre><code class="lang-python">rows[<span class="hljs-number">0</span>] <span class="hljs-comment">#The first occurrence inside 'rows'</span>
</code></pre>
<pre><code class="lang-python">[<span class="hljs-string">'CDISCPILOT01'</span>,
 <span class="hljs-string">'AE'</span>,
 <span class="hljs-string">'01-701-1015'</span>,
 <span class="hljs-number">1</span>,
 <span class="hljs-string">'E07'</span>,
 <span class="hljs-string">'アプリケーションサイトの紅斑'</span>,
 <span class="hljs-string">'APPLICATION SITE REDNESS'</span>,
 <span class="hljs-literal">None</span>,
 <span class="hljs-string">'APPLICATION SITE ERYTHEMA'</span>,
 <span class="hljs-number">12345678</span>,
 <span class="hljs-string">'HLT_0617'</span>,
 <span class="hljs-number">12345678</span>,
 <span class="hljs-string">'HLGT_0152'</span>,
 <span class="hljs-number">12345678</span>,
 <span class="hljs-string">'GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS'</span>,
 <span class="hljs-number">87654321</span>,
 <span class="hljs-string">'GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS'</span>,
 <span class="hljs-literal">None</span>,
 <span class="hljs-string">'MILD'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">''</span>,
 <span class="hljs-string">'PROBABLE'</span>,
 <span class="hljs-string">'NOT RECOVERED/NOT RESOLVED'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">'2014-01-16'</span>,
 <span class="hljs-string">'2014-01-03'</span>,
 <span class="hljs-string">''</span>,
 <span class="hljs-number">2</span>,
 <span class="hljs-literal">None</span>,
 <span class="hljs-string">'Y'</span>]
</code></pre>
<p>Notice the order of the data; it is expected that once we "link" the rows to the columns, each piece of data in this list will start to make sense. This same order will appear in all other rows found in this object, each in a separate list.</p>
<h2 id="heading-building-a-dataframe-simply">Building a DataFrame Simply</h2>
<p>To build the DataFrame, you need to keep two things in mind: 1) We already have the rows of our table in the <code>rows</code> variable, which is expected to be ordered; and 2) We have the column name definitions in the <code>columns</code> object, as dictionaries in a list. So, before we use <code>pandas</code> to finally build the DataFrame, we first need to separate what will be the column names of the table. To do this, we just need to create a <code>data</code> list, which will be populated with the labels from an iteration using the <code>columns</code> key in our first dictionary, <code>example</code>. Since <code>columns</code> is a list with several dictionaries, we just need to access each dictionary within this list and extract the <code>label</code> using the <code>object[key]</code> principle. From this, we have the labels for each column, as they are the <code>label</code> values within each dictionary.</p>
<pre><code class="lang-python">data = [] <span class="hljs-comment">#List to be populated</span>

<span class="hljs-keyword">for</span> cl <span class="hljs-keyword">in</span> example[<span class="hljs-string">'columns'</span>]: <span class="hljs-comment">#An iteraction in order to extract the labels</span>
        data.append(cl[<span class="hljs-string">'label'</span>])
</code></pre>
<pre><code class="lang-python">data <span class="hljs-comment">#See which labels appear</span>
</code></pre>
<pre><code class="lang-python">[<span class="hljs-string">'Study Identifier'</span>,
 <span class="hljs-string">'Domain Abbreviation'</span>,
 <span class="hljs-string">'Unique Subject Identifier'</span>,
 <span class="hljs-string">'Sequence Number'</span>,
 <span class="hljs-string">'Sponsor-Defined Identifier'</span>,
 <span class="hljs-string">'Reported Term for the Adverse Event'</span>,
 <span class="hljs-string">'Lowest Level Term'</span>,
 <span class="hljs-string">'Lowest Level Term Code'</span>,
 <span class="hljs-string">'Dictionary-Derived Term'</span>,
 <span class="hljs-string">'Preferred Term Code'</span>,
 <span class="hljs-string">'High Level Term'</span>,
 <span class="hljs-string">'High Level Term Code'</span>,
 <span class="hljs-string">'High Level Group Term'</span>,
 <span class="hljs-string">'High Level Group Term Code'</span>,
 <span class="hljs-string">'Body System or Organ Class'</span>,
 <span class="hljs-string">'Body System or Organ Class Code'</span>,
 <span class="hljs-string">'Primary System Organ Class'</span>,
 <span class="hljs-string">'Primary System Organ Class Code'</span>,
 <span class="hljs-string">'Severity/Intensity'</span>,
 <span class="hljs-string">'Serious Event'</span>,
 <span class="hljs-string">'Action Taken with Study Treatment'</span>,
 <span class="hljs-string">'Causality'</span>,
 <span class="hljs-string">'Outcome of Adverse Event'</span>,
 <span class="hljs-string">'Involves Cancer'</span>,
 <span class="hljs-string">'Congenital Anomaly or Birth Defect'</span>,
 <span class="hljs-string">'Persist or Signif Disability/Incapacity'</span>,
 <span class="hljs-string">'Results in Death'</span>,
 <span class="hljs-string">'Requires or Prolongs Hospitalization'</span>,
 <span class="hljs-string">'Is Life Threatening'</span>,
 <span class="hljs-string">'Occurred with Overdose'</span>,
 <span class="hljs-string">'Date/Time of Collection'</span>,
 <span class="hljs-string">'Start Date/Time of Adverse Event'</span>,
 <span class="hljs-string">'End Date/Time of Adverse Event'</span>,
 <span class="hljs-string">'Study Day of Start of Adverse Event'</span>,
 <span class="hljs-string">'Study Day of End of Adverse Event'</span>,
 <span class="hljs-string">'TREATMENT EMERGENT FLAG'</span>]
</code></pre>
<p>Once this is done, the return we see is a list of names that we will use to identify each column of our future DataFrame.</p>
<p>With this process completed and all this data in hand, it's time to put everything together in a single DataFrame. To do this, we'll use the <code>pd.DataFrame()</code> function, where we will specify where the data for the rows is located, using <code>rows</code>, and the column names, using the <code>columns</code> argument and the <code>data</code> object.</p>
<pre><code class="lang-python">df = pd.DataFrame(rows, columns=data)
</code></pre>
<p>Once everything is integrated into a DataFrame, simply save it in your preferred format. From here, the semi-structured JSON data becomes structured spreadsheet data.</p>
<pre><code class="lang-python"><span class="hljs-comment">## Exporting</span>

df.to_csv(<span class="hljs-string">'df.csv'</span>) <span class="hljs-comment">#.csv file</span>
df.to_excel(<span class="hljs-string">'df.xlsx'</span>) <span class="hljs-comment">#.xlsx file</span>
df.to_parquet(<span class="hljs-string">'df.parquet'</span>) <span class="hljs-comment">#.parquet file</span>
</code></pre>
<hr />
<h1 id="heading-notes">Notes</h1>
<p>1. More information about this can be found on the official JSON page: <a target="_blank" href="https://www.json.org/json-pt.html">https://www.json.org/</a> <a class="post-section-overview" href="#one">↩</a></p>
<p>2. PHUSE is a nonprofit organization that brings together people who share ideas and solutions involving clinical data, such as analyzing and subsequently reporting it. Many innovations in data involving clinical trials will certainly come from this organization; therefore, it's definitely worth following them at <a target="_blank" href="https://phuse.global/">https://phuse.global/</a>. <a class="post-section-overview" href="#two">↩</a></p>
<p>3. PHUSE. <a target="_blank" href="https://phuse.s3.eu-central-1.amazonaws.com/Deliverables/Optimizing+the+Use+of+Data+Standards/WP-88+Dataset-JSON+Report.pdf">https://phuse.s3.eu-central-1.amazonaws.com/Deliverables/Optimizing+the+Use+of+Data+Standards/WP-88+Dataset-JSON+Report.pdf</a> <a class="post-section-overview" href="#three">↩</a></p>
<p>4. "Another concern raised about Dataset-XML has been that the metadata - Define-XML - is completely separated from the data. To be able to process a Dataset-XML file one always needs the associated Define-XML document." Lex Jansen (<a target="_blank" href="https://www.lexjansen.com/pharmasug/2022/AD/PharmaSUG-2022-AD-150_ppt.pdf">https://www.lexjansen.com/pharmasug/2022/AD/PharmaSUG-2022-AD-150_ppt.pdf</a>) <a class="post-section-overview" href="#four">↩</a></p>
<p>5. "Python JSON is similar to a Python dictionary in that it stores data in key-value pairs enclosed in curly brackets ({}). However, double quotation marks around the JSON key are required in this case." Como visto em <a target="_blank" href="https://www.boardinfinity.com/blog/dict-to-json-in-python/">https://www.boardinfinity.com/blog/dict-to-json-in-python/</a> <a class="post-section-overview" href="#five">↩</a></p>
<p>6. The differences between JSON objects and <code>dict</code> can be seen in detail in this GeeksforGeeks article: <a target="_blank" href="https://www.geeksforgeeks.org/difference-between-json-and-dictionary-in-python/">https://www.geeksforgeeks.org/difference-between-json-and-dictionary-in-python/</a> <a class="post-section-overview" href="#six">↩</a></p>
<p>7. The object identifier varies from document to document, EDC to EDC. Using a specific EDC, OpenClinica, we see how this issue is addressed in the documentation here: <a target="_blank" href="https://docs.openclinica.com/3-1-technical-documents/openclinica-and-cdisc-odm-specifications/openclinica-and-cdisc-odm-specifications-cdisc-odm-representation-openclin-6/">https://docs.openclinica.com/3-1-technical-documents/openclinica-and-cdisc-odm-specifications/openclinica-and-cdisc-odm-specifications-cdisc-odm-representation-openclin-6/</a> <a class="post-section-overview" href="#seven">↩</a></p>
]]></content:encoded></item><item><title><![CDATA[JSON na Prática: Lidando com o Dataset-JSON em Python]]></title><description><![CDATA[Contexto
Em estudos clínicos, é comum trabalharmos com conjuntos de dados que podem vir em variados formatos, dependendo do que o sistema EDC escolhido consegue oferecer. Entretanto, em algumas situações, será preciso extrair um conjunto de dados com...]]></description><link>https://blog.matheusyuri.pro/json-na-pratica</link><guid isPermaLink="true">https://blog.matheusyuri.pro/json-na-pratica</guid><category><![CDATA[json]]></category><category><![CDATA[json-schema]]></category><category><![CDATA[CDISC]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[Databases]]></category><category><![CDATA[data structures]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Tue, 19 Nov 2024 03:24:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731987241227/dc7e3404-6b9a-4761-bb57-ed779899e44a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-contexto">Contexto</h1>
<p>Em estudos clínicos, é comum trabalharmos com conjuntos de dados que podem vir em variados formatos, dependendo do que o sistema <a target="_blank" href="https://en.wikipedia.org/wiki/Electronic_data_capture">EDC</a> escolhido consegue oferecer. Entretanto, em algumas situações, será preciso extrair um conjunto de dados completo, de acordo com o que as entidades regulatórias exigem nas submissões de aprovação do uso de medicamentos e vacinas, principalmente. Dentre os formatos que aparecem como opções mais frequentes, estão o XML <a target="_blank" href="https://hashnode.com/post/clzjxe1zi000f09l44nqga8ip">(que já vimos anteriormente)</a> , e o JSON. Para aliviar um pouco mais do desespero que às vezes bate quando enfrentamos esses "monstros", hoje é a vez de ver na prática como lidar com um arquivo JSON.</p>
<h1 id="heading-o-que-e-json">O que é JSON?</h1>
<p><strong>JSON</strong> é a sigla para <em>JavaScript Object Notation</em>, uma representação de dados que, assim como o <strong>XML</strong>, pode ser utilizada para transmissões de dados. Como o próprio nome aponta, é baseado em um subconjunto da linguagem JavaScript; no entanto, possui uma estrutura universal, podendo ser lida e manipulada por várias linguagens de programação <a class="post-section-overview" href="#um"><sup>1</sup></a>.</p>
<h2 id="heading-dataset-json">Dataset-JSON</h2>
<p>O <strong>Dataset-JSON</strong> é uma iniciativa <a target="_blank" href="https://www.cdisc.org/dataset-json">em desenvolvimento contínuo</a> liderada por CDISC e PHUSE <a class="post-section-overview" href="#dois"><sup>2</sup></a>, com o objetivo de estabelecer uma alternativa mais leve, rápida, e legível para humanos, dos modelos de transferência de dados clínicos utilizados atualmente (a saber, SAS e Dataset-XML, este último já abordado no blog).</p>
<h2 id="heading-diferencas-entre-json-e-xml-para-armazenamento-e-transferencia-de-dados">Diferenças entre JSON e XML para armazenamento e transferência de dados</h2>
<p>Especialmente nos casos de dados de estudos clínicos, várias fontes apontam que o formato JSON leva certas vantagens sobre o formato XML. Podemos elencar alguns aqui:</p>
<ul>
<li><p>O <strong>XML</strong>, embora já seja um avanço frente a modelos de dados clínicos mais antigos, ainda é um formato de arquivo grande, muito em função da sua natureza verbosa; em uma mesma tag, por exemplo, é possível ter mais de um atributo que represente informações importantes (esse problema, inclusive, foi abordado no segundo post sobre o XML no blog). O <strong>JSON</strong> possui uma estrutura mais simples e flexível, podendo armazenar a mesma quantidade de informações que um XML num arquivo menor e de leitura mais fácil, economizando memória e energia;</p>
</li>
<li><p>O <strong>JSON</strong> é inteiramente compatível com APIs, podendo ser visto em versões de EDCs mais novos (como o OpenClinica a partir da versão v. 4.x, e as versões mais novas dos REDCap Acadêmico e Cloud), facilitando a transmissão de dados, sem a necessidade de obrigatoriamente baixar arquivos manualmente <a class="post-section-overview" href="#tres"><sup>3</sup></a>. O XML, embora esteja presente em algumas APIs, não possui a mesma presença e facilidade do JSON;</p>
</li>
<li><p>O <strong>JSON</strong> comporta informações básicas sobre as variáveis em seu próprio arquivo; para o XML, embora isso seja possível (como vimos em posts anteriores), não é necessariamente a regra, sendo dependente de arquivos externos <a class="post-section-overview" href="#quatro"><sup>4</sup></a>;</p>
</li>
<li><p>O <strong>XML</strong> permite a adição de novos <em>namespaces</em>, metadados e outras informações, mas sua estrutura rígida é um fator limitante crítico para tanto. O JSON é muito mais flexível, tendo uma estrutura mais simples e amigável para inserir novos dados.</p>
</li>
</ul>
<p>Vejamos exemplos de como os elementos que formam arquivos XML e JSON são distribuídos na memória quando lidos. O primeiro caso é de uma árvore parecida com o esquema de árvore ODM de arquivos XML que já vimos antes. A árvore XML possui um grau alto de complexidade, evidenciada no diagrama abaixo, sendo que são muitos os elementos que precisam ser armazenados em espaços próprios na memória, fazendo com que seja preciso fazer mais "saltos" entre elementos para conseguir chegar ao dado que se quer.</p>
<p><img src="https://mermaid.ink/img/pako:eNptkbFOAzEMQH8l8twOlO2QkGhzLQxdKBMXBvfi3kW6JKfUGVDVr-IT-DHSnKCRiif7PVuW7BO0XhNU0AUce_EmH5QTKY5xP5Et2e-vYHDCl3hqXr3njwKI-fxRLJt6IEuO727U6lctCrXMSja7uP9ncJVtXdjFjV0X9r6wdbabRiJjgdcZP09YXLnM_KVsJ6dhBpaCRaPTcU4XrID7tEtBlVJHkQMOCpQ7p1aM7HefroWKQ6QZBB-7HqoDDsdUxVEjkzSYTmr_6Iju3ftrTdqwD9vpHa13B9PB-QfXMnlv?type=png" alt="&quot;Esquema de distribuição dos elementos de um arquivo XML na memória.&quot;" class="image--center mx-auto" /></p>
<p>Já quando falamos da árvore de um arquivo JSON, é possível perceber de cara uma redução na complexidade: os dados estão junto dos sub-elementos, fazendo com que o espaço ocupado na memória seja menor, assim como a quantidade de "saltos" feitos aqui, economizando tempo e energia. O esquema está no diagrama abaixo.</p>
<p><img src="https://mermaid.ink/img/pako:eNplkDEOwjAMRa8SeaYDsAUJCWjZWCgTDYMhhlZqkio4A0KciiNwMUIroAhP9v9PtvyvcHCaQMLJY1OKTTpRVsQ6h32nrMg87r7CTn7VrFg7xzuRJFMxL7KaDFke7iZfYt56iyIP-7ctRYqM_1Dag0b_0KyFsveVUd_LWm_ZWzD-XUBWwwAMeYOVji9eX7ICLiOsQMbWUmCPtQJlbxHFwC6_2ANI9oEG4F04lSCPWJ_jFBqNTGmFMRjzURu0W-e-M-mKnV91obbZ3p5B5Wzq?type=png" alt="Esquema de distribuição dos elementos de um arquivo JSON na memória." class="image--center mx-auto" /></p>
<p>Podemos, a partir daqui, fornecer um resumo dessa comparação:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Aspecto</strong></td><td><strong>Dataset-XML</strong></td><td><strong>Dataset-JSON</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Estrutura</strong></td><td>Árvore hierárquica com ponteiros para pais/filhos</td><td>Objetos aninhados sem ponteiros explícitos</td></tr>
<tr>
<td><strong>Uso de Memória</strong></td><td>Alto (4-5x maior que o arquivo original)</td><td>Baixo (mais próximo do tamanho original)</td></tr>
<tr>
<td><strong>Complexidade</strong></td><td>Alta (necessário manter relações entre nós)</td><td>Baixa (estrutura plana com arrays e dicionários)</td></tr>
<tr>
<td><strong>Eficiência</strong></td><td>Menos eficiente em termos de acesso</td><td>Mais eficiente devido à simplicidade da estrutura</td></tr>
</tbody>
</table>
</div><h1 id="heading-usando-python-para-lidar-com-json">Usando Python para lidar com JSON</h1>
<h2 id="heading-dados-que-serao-utilizados">Dados que serão utilizados</h2>
<p>Os dados que utilizaremos neste artigo ainda são do repositório do CDISC no GitHub, mas estão em uma pasta à parte dedicada aos arquivos Dataset-JSON. Além do exemplo que será nosso foco aqui, há muitos outros datasets que podem ser visualizados, extraídos, e manipulados à disposição.</p>
<h2 id="heading-bibliotecas-a-serem-importadas">Bibliotecas a serem importadas</h2>
<p>Ao usarmos o Python para lidar com dados advindos de arquivos JSON, utilizaremos uma biblioteca em específico que é exatamente dedicada a esse tipo de documento: <code>json</code>. Esta é uma biblioteca nativa do Python; portanto, se você está utilizando WinPython ou Anaconda, é muito provável que consiga acessar a ferramenta apenas com uma importação. As outras bibliotecas que serão importadas já são de conhecimento nosso: <code>requests</code> e <code>pandas</code>.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests, json
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
</code></pre>
<h2 id="heading-adquirindo-e-explorando-os-dados">Adquirindo e explorando os dados</h2>
<p>Para obter os dados que iremos analisar, é possível utilizar passos semelhantes ao que já vimos em posts anteriores, usando a biblioteca <code>requests</code>. Com a função <code>requests.get()</code> enviamos uma requisição ao GitHub para obtermos o arquivo JSON que queremos, e, uma vez bem-sucedida essa requisição, podemos armazenar o conteúdo da mesma em uma variável, <code>example</code>.</p>
<p>Como retratado antes, diferentemente daquilo que fazemos com arquivos XML, usaremos o pacote <code>json</code> para lermos o arquivo resultante da requisição. Para este caso, usamos a função <code>json.loads()</code>, como abaixo.</p>
<pre><code class="lang-python">example = requests.get(<span class="hljs-string">'https://github.com/cdisc-org/DataExchange-DatasetJson/raw/refs/heads/master/examples/i18n/ae.json'</span>)
example = example.content
example = json.loads(example)
</code></pre>
<p>O resultado desse "carregamento" <a target="_blank" href="https://www.boardinfinity.com/blog/dict-to-json-in-python/">é um objeto parecido com o <code>dict</code> do Python</a>, um dicionário <a class="post-section-overview" href="#cinco"><sup>5</sup></a> <a class="post-section-overview" href="#seis"><sup>6</sup></a>; esse é um dos tipos propostos para JSON quando da leitura do mesmo por algum software ou pacote de linguagem. Neste dicionário, encontraremos todas as informações de que precisamos para identificar os dados e colocá-los em um DataFrame legível e explorável.</p>
<p>Se explorarmos esse dicionário em uma IDE como o <a target="_blank" href="https://www.spyder-ide.org/">Spyder</a>, que está disponível tanto no WinPython, quanto no Anaconda, veremos uma estrutura chave-valor clássica de um dicionário, mas estaremos também vendo outras coisas que nos interessam aqui, conforme a imagem abaixo.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731986675802/9794680b-cc39-4608-bddc-2cc7f38e6d5e.png" alt class="image--center mx-auto" /></p>
<p>Desde a versão dos metadados, até o número de registros contidos no arquivo JSON, várias informações essenciais do arquivo; foquemo-nos, no entanto, em apenas duas chaves: <code>columns</code> e <code>rows</code>. Nesses valores estarão aquilo que utilizaremos para montarmos o DataFrame em pandas que poderemos explorar mais à frente.</p>
<h2 id="heading-acessando-dados-dentro-do-json">Acessando dados dentro do JSON</h2>
<p>Para que seja possível acessar os dados de <code>rows</code> e <code>columns</code> dentro do objeto <code>example</code>, basta que sigamos a lógica de um dicionário em Python, como foi relatado antes. Usando o método <code>object[key]</code>, ou <code>objeto[chave]</code>, podemos acessar os dados que queremos dentro do dicionário <code>example</code>, usando algo como o bloco abaixo:</p>
<pre><code class="lang-python">columns = example[<span class="hljs-string">'columns'</span>]
rows = example[<span class="hljs-string">'rows'</span>]
</code></pre>
<p>Com isso, podemos ter acesso pleno ao conteúdo que iremos utilizar para montar o DataFrame. Se invocarmos o objeto <code>columns</code> no console, será possível ver todo o conteúdo que ele possui.</p>
<pre><code class="lang-python">columns
</code></pre>
<pre><code class="lang-python">[{<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.STUDYID'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'STUDYID'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Study Identifier'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">12</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.DOMAIN'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'DOMAIN'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Domain Abbreviation'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">2</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.USUBJID'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'USUBJID'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Unique Subject Identifier'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">11</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESEQ'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESEQ'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Sequence Number'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESPID'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESPID'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Sponsor-Defined Identifier'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">3</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AETERM'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AETERM'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Reported Term for the Adverse Event'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">200</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AELLT'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AELLT'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Lowest Level Term'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">100</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AELLTCD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AELLTCD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Lowest Level Term Code'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEDECOD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEDECOD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Dictionary-Derived Term'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">200</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEPTCD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEPTCD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Preferred Term Code'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEHLT'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEHLT'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'High Level Term'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">100</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEHLTCD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEHLTCD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'High Level Term Code'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEHLGT'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEHLGT'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'High Level Group Term'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">100</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEHLGTCD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEHLGTCD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'High Level Group Term Code'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEBODSYS'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEBODSYS'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Body System or Organ Class'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">67</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEBDSYCD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEBDSYCD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Body System or Organ Class Code'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESOC'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESOC'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Primary System Organ Class'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">100</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESOCCD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESOCCD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Primary System Organ Class Code'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESEV'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESEV'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Severity/Intensity'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">8</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESER'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESER'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Serious Event'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEACN'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEACN'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Action Taken with Study Treatment'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">30</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEREL'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEREL'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Causality'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">8</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEOUT'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEOUT'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Outcome of Adverse Event'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">200</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESCAN'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESCAN'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Involves Cancer'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESCONG'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESCONG'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Congenital Anomaly or Birth Defect'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESDISAB'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESDISAB'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Persist or Signif Disability/Incapacity'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESDTH'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESDTH'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Results in Death'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESHOSP'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESHOSP'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Requires or Prolongs Hospitalization'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESLIFE'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESLIFE'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Is Life Threatening'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESOD'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESOD'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Occurred with Overdose'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEDTC'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEDTC'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Date/Time of Collection'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">10</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESTDTC'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESTDTC'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Start Date/Time of Adverse Event'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">10</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEENDTC'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEENDTC'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'End Date/Time of Adverse Event'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">10</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AESTDY'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AESTDY'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Study Day of Start of Adverse Event'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AEENDY'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AEENDY'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'Study Day of End of Adverse Event'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'float'</span>},
 {<span class="hljs-string">'itemOID'</span>: <span class="hljs-string">'IT.AE.AETRTEM'</span>,
  <span class="hljs-string">'name'</span>: <span class="hljs-string">'AETRTEM'</span>,
  <span class="hljs-string">'label'</span>: <span class="hljs-string">'TREATMENT EMERGENT FLAG'</span>,
  <span class="hljs-string">'dataType'</span>: <span class="hljs-string">'string'</span>,
  <span class="hljs-string">'length'</span>: <span class="hljs-number">1</span>}]
</code></pre>
<p>Perceba que, quando acessamos o <code>columns</code>, não tempos apenas o nome da coluna, mas também o que ela significa (através do <code>label</code>), tipo de dado (através do <code>dataType</code>), além do OID, que é o identificador do objeto <a class="post-section-overview" href="#sete"><sup>7</sup></a>. Isso evidencia a facilidade do JSON de comportar e acessar os metadados do arquivo, uma vantagem frente ao XML que, embora exista a possibilidade de acesso dos metadados em um mesmo arquivo, isso não é feito de forma tão facilitada.</p>
<p>Indo adiante, para vermos o que o objeto <code>rows</code> possui, usamos a mesmo método de antes. Como é esperado que o número de registros seja grande (ao verificarmos na chave <code>records</code>do dicionário, temos 1191 registros!), veremos apenas a primeira ocorrência, neste caso.</p>
<pre><code class="lang-python">rows[<span class="hljs-number">0</span>] <span class="hljs-comment">#A primeira ocorrência dentro da lista 'rows'</span>
</code></pre>
<pre><code class="lang-python">[<span class="hljs-string">'CDISCPILOT01'</span>,
 <span class="hljs-string">'AE'</span>,
 <span class="hljs-string">'01-701-1015'</span>,
 <span class="hljs-number">1</span>,
 <span class="hljs-string">'E07'</span>,
 <span class="hljs-string">'アプリケーションサイトの紅斑'</span>,
 <span class="hljs-string">'APPLICATION SITE REDNESS'</span>,
 <span class="hljs-literal">None</span>,
 <span class="hljs-string">'APPLICATION SITE ERYTHEMA'</span>,
 <span class="hljs-number">12345678</span>,
 <span class="hljs-string">'HLT_0617'</span>,
 <span class="hljs-number">12345678</span>,
 <span class="hljs-string">'HLGT_0152'</span>,
 <span class="hljs-number">12345678</span>,
 <span class="hljs-string">'GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS'</span>,
 <span class="hljs-number">87654321</span>,
 <span class="hljs-string">'GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS'</span>,
 <span class="hljs-literal">None</span>,
 <span class="hljs-string">'MILD'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">''</span>,
 <span class="hljs-string">'PROBABLE'</span>,
 <span class="hljs-string">'NOT RECOVERED/NOT RESOLVED'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">'N'</span>,
 <span class="hljs-string">'2014-01-16'</span>,
 <span class="hljs-string">'2014-01-03'</span>,
 <span class="hljs-string">''</span>,
 <span class="hljs-number">2</span>,
 <span class="hljs-literal">None</span>,
 <span class="hljs-string">'Y'</span>]
</code></pre>
<p>Perceba a ordem em que estão os dados; é de se esperar que, uma vez que "liguemos" as linhas às colunas, cada dado nessa lista comece a fazer sentido. Essa mesma ordem aparecerá em todas as outras linhas encontradas nesse objeto, que estão cada uma em uma lista separada.</p>
<h2 id="heading-montando-um-dataframe-de-um-jeito-simples">Montando um DataFrame de um jeito simples</h2>
<p>Para montarmos o DataFrame, primeiro é preciso ter duas coisas em mente: 1) Já temos as linhas da nossa tabela na variável <code>rows</code>, de forma (que se espera ser) ordenada; e 2) Temos as definições de nomes das colunas no objeto <code>columns</code>, em forma de dicionários em uma lista. Então, antes de usarmos o <code>pandas</code> para montarmos de vez o DataFrame, primeiro precisamos separar aquilo que serão os nomes das colunas da tabela. Para isso, basta criarmos uma lista <code>data</code>, que será populada com os rótulos, ou <code>labels</code> de uma iteração a partir da chave <code>columns</code> no nosso primeiro dicionário, <code>example</code>. Sendo <code>columns</code> uma lista com vários dicionários, basta com que a gente acesse cada dicionário dentro dessa lista, e extraia o <code>label</code> usando o princípio <code>objeto[chave]</code>. A partir disso, temos os rótulos de cada coluna, uma vez que são os valores de <code>label</code> dentro de cada dicionário.</p>
<pre><code class="lang-python">data = [] <span class="hljs-comment">#A lista a ser populada</span>

<span class="hljs-keyword">for</span> cl <span class="hljs-keyword">in</span> example[<span class="hljs-string">'columns'</span>]: <span class="hljs-comment">#Iteração para extrairmos os rótulos</span>
        data.append(cl[<span class="hljs-string">'label'</span>])
</code></pre>
<pre><code class="lang-python">data <span class="hljs-comment">#Acessar os dados da lista já populada</span>
</code></pre>
<pre><code class="lang-python">[<span class="hljs-string">'Study Identifier'</span>,
 <span class="hljs-string">'Domain Abbreviation'</span>,
 <span class="hljs-string">'Unique Subject Identifier'</span>,
 <span class="hljs-string">'Sequence Number'</span>,
 <span class="hljs-string">'Sponsor-Defined Identifier'</span>,
 <span class="hljs-string">'Reported Term for the Adverse Event'</span>,
 <span class="hljs-string">'Lowest Level Term'</span>,
 <span class="hljs-string">'Lowest Level Term Code'</span>,
 <span class="hljs-string">'Dictionary-Derived Term'</span>,
 <span class="hljs-string">'Preferred Term Code'</span>,
 <span class="hljs-string">'High Level Term'</span>,
 <span class="hljs-string">'High Level Term Code'</span>,
 <span class="hljs-string">'High Level Group Term'</span>,
 <span class="hljs-string">'High Level Group Term Code'</span>,
 <span class="hljs-string">'Body System or Organ Class'</span>,
 <span class="hljs-string">'Body System or Organ Class Code'</span>,
 <span class="hljs-string">'Primary System Organ Class'</span>,
 <span class="hljs-string">'Primary System Organ Class Code'</span>,
 <span class="hljs-string">'Severity/Intensity'</span>,
 <span class="hljs-string">'Serious Event'</span>,
 <span class="hljs-string">'Action Taken with Study Treatment'</span>,
 <span class="hljs-string">'Causality'</span>,
 <span class="hljs-string">'Outcome of Adverse Event'</span>,
 <span class="hljs-string">'Involves Cancer'</span>,
 <span class="hljs-string">'Congenital Anomaly or Birth Defect'</span>,
 <span class="hljs-string">'Persist or Signif Disability/Incapacity'</span>,
 <span class="hljs-string">'Results in Death'</span>,
 <span class="hljs-string">'Requires or Prolongs Hospitalization'</span>,
 <span class="hljs-string">'Is Life Threatening'</span>,
 <span class="hljs-string">'Occurred with Overdose'</span>,
 <span class="hljs-string">'Date/Time of Collection'</span>,
 <span class="hljs-string">'Start Date/Time of Adverse Event'</span>,
 <span class="hljs-string">'End Date/Time of Adverse Event'</span>,
 <span class="hljs-string">'Study Day of Start of Adverse Event'</span>,
 <span class="hljs-string">'Study Day of End of Adverse Event'</span>,
 <span class="hljs-string">'TREATMENT EMERGENT FLAG'</span>]
</code></pre>
<p>Feito isso, o retorno que vemos é uma lista de nomes que utilizaremos para identificar cada coluna do nosso futuro DataFrame.</p>
<p>Com todo esse processo realizado, e com todos esses dados em mãos, já é hora de juntarmos tudo isso em um mesmo DataFrame; para tanto, lançaremos mão da função <code>pd.DataFrame()</code>, onde indicaremos onde está os dados que estarão nas linhas, <code>rows</code>, e os nomes das colunas, utilizando o argumento <code>columns</code> e o objeto <code>data</code>.</p>
<pre><code class="lang-python">df = pd.DataFrame(rows, columns=data)
</code></pre>
<p>Uma vez integrado tudo em um DataFrame, basta salvar com o formato de preferência. A partir daqui, os dados semi-estruturados do JSON passam a ser dados estruturados de uma planilha.</p>
<pre><code class="lang-python"><span class="hljs-comment">## Exportando</span>

df.to_csv(<span class="hljs-string">'df.csv'</span>) <span class="hljs-comment">#Arquivo .csv</span>
df.to_excel(<span class="hljs-string">'df.xlsx'</span>) <span class="hljs-comment">#Arquivo .xlsx</span>
df.to_parquet(<span class="hljs-string">'df.parquet'</span>) <span class="hljs-comment">#Arquivo .parquet</span>
</code></pre>
<hr />
<h1 id="heading-notas-do-artigo">Notas do artigo</h1>
<p>1. Mais informações sobre isso podem ser vistas na página oficial do JSON, que está traduzida em português, inclusive: https://www.json.org/json-pt.html <a class="post-section-overview" href="#um">↩</a></p>
<p>2. O PHUSE é uma associação sem fins lucrativos que reúne pessoas que compartilham ideias e soluções envolvendo dados clínicos, como analisá-los e, posteriormente reportá-los. Muitas das inovações em dados envolvendo ensaios clínicos, certamente, virão dessa associação; portanto, vale muito a pena acompanhá-los via https://phuse.global/. <a class="post-section-overview" href="#dois">↩</a></p>
<p>3. PHUSE. https://phuse.s3.eu-central-1.amazonaws.com/Deliverables/Optimizing+the+Use+of+Data+Standards/WP-88+Dataset-JSON+Report.pdf <a class="post-section-overview" href="#tres">↩</a></p>
<p>4. "Another concern raised about Dataset-XML has been that the metadata - Define-XML - is completely separated from the data. To be able to process a Dataset-XML file one always needs the associated Define-XML document." Lex Jansen (https://www.lexjansen.com/pharmasug/2022/AD/PharmaSUG-2022-AD-150_ppt.pdf) <a class="post-section-overview" href="#quatro">↩</a></p>
<p>5. "Python JSON is similar to a Python dictionary in that it stores data in key-value pairs enclosed in curly brackets ({}). However, double quotation marks around the JSON key are required in this case." Como visto em https://www.boardinfinity.com/blog/dict-to-json-in-python/ <a class="post-section-overview" href="#cinco">↩</a></p>
<p>6. As diferenças entre objetos JSON e <code>dict</code> podem ser vistas neste artigo do GeeksforGeeks, de forma detalhada: https://www.geeksforgeeks.org/difference-between-json-and-dictionary-in-python/ <a class="post-section-overview" href="#seis">↩</a></p>
<p>7. O identificador do objeto varia de documento para documento, EDC para EDC. Usando um EDC específico, o OpenClinica, vemos como esse assunto é tratado na documentação, aqui: https://docs.openclinica.com/3-1-technical-documents/openclinica-and-cdisc-odm-specifications/openclinica-and-cdisc-odm-specifications-cdisc-odm-representation-openclin-6/ <a class="post-section-overview" href="#sete">↩</a></p>
]]></content:encoded></item><item><title><![CDATA[Mastering XML with Python (2): Doing (much) more with (much) less]]></title><description><![CDATA[In the last post, we saw how to handle ODM-XML files using some Python libraries, making the process less daunting and simpler.
## Do you remember these libraries? ##
import requests
from lxml import etree
import pandas as pd

These libraries (especi...]]></description><link>https://blog.matheusyuri.pro/mastering-xml-with-python-2</link><guid isPermaLink="true">https://blog.matheusyuri.pro/mastering-xml-with-python-2</guid><category><![CDATA[Data Science]]></category><category><![CDATA[Databases]]></category><category><![CDATA[data structures]]></category><category><![CDATA[CDISC]]></category><category><![CDATA[Python]]></category><category><![CDATA[xml]]></category><category><![CDATA[xml-parsing]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Tue, 05 Nov 2024 18:04:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730829736103/f72f1073-1a4f-475a-942e-02dc5e5fe6d6.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the <a target="_blank" href="https://blog.matheusyuri.pro/xml-na-pratica">last post</a>, we saw how to handle ODM-XML files using some Python libraries, making the process less daunting and simpler.</p>
<pre><code class="lang-python"><span class="hljs-comment">## Do you remember these libraries? ##</span>
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> lxml <span class="hljs-keyword">import</span> etree
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
</code></pre>
<p>These libraries (especially <code>pandas</code> and <code>lxml.etree</code>) are designed to optimize the construction and manipulation of datasets contained in an XML document. However, we might encounter some obstacles along the way that were not addressed in the previous article. Here are a few:</p>
<ul>
<li><p><strong>The XML document is huge</strong>: Previously, we used a file that was small in size; we know that in real life, things might not always be like that. We might end up with a file that is 1GB or larger;</p>
</li>
<li><p><strong>You don't need all the data contained in the file</strong>: To manipulate an XML document, libraries like <code>lxml</code> and <code>ElementTree</code> need, by the nature of this type of file, to read and interpret an XML from start to finish. For reasons like the problem mentioned above, this costs time and memory, affecting the performance of your Python script.</p>
</li>
<li><p><strong>You don't have a robust machine available</strong>: The two problems above are much harder to solve when we have a more limited machine. Using platforms like <a target="_blank" href="https://colab.research.google.com/">Google Colab</a> can be a workaround for this, but we can't always rely on this resource.</p>
</li>
</ul>
<p>From this, you might think something like, "I'm back to square one; how am I going to manipulate this darn XML and get the data I need? Will I have to look for an alternative other than Python?"</p>
<p>The goal of this article is to show that it's not time to give up on Python yet. By changing a few things in the code, you will certainly have another chance to tackle the "monsters" of XML and finally extract the much-anticipated data and information.</p>
<h2 id="heading-understanding-the-obstacle-itself">Understanding the obstacle itself</h2>
<p>To start, let's focus on some of the first lines of code we're using:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> lxml <span class="hljs-keyword">import</span> etree
<span class="hljs-keyword">import</span> requests

url = <span class="hljs-string">'https://github.com/cdisc-org/DataExchange-ODM/raw/main/examples/Demographics_RACE/Demographics_RACE_check_all_that_apply.xml'</span> <span class="hljs-comment">#Fonte do arquivo .xml que estamos utilizando</span>
response = requests.get(url) <span class="hljs-comment">#HTTP Request</span>

tree = response.content <span class="hljs-comment">#The request content</span>
</code></pre>
<p>This block of code, as seen above, does three things: <strong>1)</strong> Stores a <code>string</code> of a GitHub URL; <strong>2)</strong> Makes a request to this URL via <a target="_blank" href="https://requests.readthedocs.io/"><code>requests</code></a> to get its content; and <strong>3)</strong> Stores the content of the request in a variable (i.e., the XML file from which we will extract data).</p>
<p>The next step is to transform the content of the <code>tree</code> variable into something that can be read and explored by <a target="_blank" href="https://lxml.de/"><code>lxml</code></a>, using the <code>XML</code> function. Like this:</p>
<pre><code class="lang-python">tree = etree.XML(tree, etree.XMLParser(remove_comments=<span class="hljs-literal">True</span>))
</code></pre>
<pre><code class="lang-python">print(tree)
&lt;Element {http://www.cdisc.org/ns/odm/v2<span class="hljs-number">.0</span>}ODM at <span class="hljs-number">0x145a22f7a80</span>&gt;
</code></pre>
<p>The process of <a target="_blank" href="https://pymotw.com/3/xml.etree.ElementTree/parse.html"><em>parsing</em></a>, which is done here by <code>lxml.etree</code>, involves transforming the content extracted from the GitHub URL into an ODM tree with all its elements. This allows us to fully explore the content of the entire XML document since the element tree will be in the computer's memory, ready to be used...</p>
<p>... and that's where the problem might be.</p>
<h2 id="heading-understanding-the-size-of-the-obstacle">Understanding the size of the obstacle</h2>
<p>As mentioned earlier, the example we're using can be considered small in various ways. Besides the size, we can assume that the ODM tree resulting from the parsing isn't very large either. Transferring the example to your computer and running the entire script, it's possible that the processing will be fast and won't take up much memory.</p>
<p>For more real-life scenarios, it's not always like this. From personal experience, I've had to deal with XML files that, once transformed into pandas DataFrames, had <strong>more than 8 million rows</strong>. To give you an idea, an Excel spreadsheet has a row limit of just over 1 million. A real "monster."</p>
<p>For the ODM tree to be used through an <code>lxml</code> <code>parse</code>, it needs to be completely "unpacked," requiring memory allocation not only for the root node (which can be seen in this case using the <code>tree.tag</code> attribute in <code>lxml</code>) but also for the child nodes, or <em>children</em>, of the entire structure. This allocation not only adds complexity but can also consume a lot of the computer's memory (an example of how all this would be distributed in memory is illustrated in the diagram below).</p>
<p><a target="_blank" href="https://mermaid.live/edit#pako:eNqNk1trwjAUgP9KiK91MB2CHQx68TbWDaaMQetDmp7aYtpImmwT8b8vvbh1OtTkoSfn-84htD07THkE2MQrQTYJWthBjvQqVFgnQAqAm3fvqc6Xy_IXXBKGrA-SMhIyQB5kXGyXLQV1uw_I9t0XD82lUFQqAS1uV9zxXzmX6FlfoMWcirm-k6QsqiC6XaJjPmrzXqvcrfDYt6QUaagkFCdw4r8Rpv6AUQWm_1fVcHZa9RsVcqvfg4XilDGzEw_LbRRS8DWYnX6_f2zajQmDuB_H50ynMSnV7lnTbczhkNLz5uhqc9yYg0F44Z6Tq83p1ebsggl5FOR1eHhSRorChRhl1T9pM07Xh69yV-52lybufqaRTMze5uu-1QRZxmO7S4mwgTMQGUkjPTG7MhNgmUAGATZ1mIOSgrAAB_leq0RJPt_mFJt6BMDAgqtVgs2YsEKf1CYiEtyU6EHLfrIQpZILr57JajT333qrElU"><img src="https://mermaid.ink/img/pako:eNqNk1trwjAUgP9KiK91MB2CHQx68TbWDaaMQetDmp7aYtpImmwT8b8vvbh1OtTkoSfn-84htD07THkE2MQrQTYJWthBjvQqVFgnQAqAm3fvqc6Xy_IXXBKGrA-SMhIyQB5kXGyXLQV1uw_I9t0XD82lUFQqAS1uV9zxXzmX6FlfoMWcirm-k6QsqiC6XaJjPmrzXqvcrfDYt6QUaagkFCdw4r8Rpv6AUQWm_1fVcHZa9RsVcqvfg4XilDGzEw_LbRRS8DWYnX6_f2zajQmDuB_H50ynMSnV7lnTbczhkNLz5uhqc9yYg0F44Z6Tq83p1ebsggl5FOR1eHhSRorChRhl1T9pM07Xh69yV-52lybufqaRTMze5uu-1QRZxmO7S4mwgTMQGUkjPTG7MhNgmUAGATZ1mIOSgrAAB_leq0RJPt_mFJt6BMDAgqtVgs2YsEKf1CYiEtyU6EHLfrIQpZILr57JajT333qrElU?type=png" alt /></a></p>
<h2 id="heading-the-obstacle-in-the-way-starts-to-become-the-way">The obstacle in the way starts to become the way</h2>
<p>The idea here is to open the XML's structural tree without storing it all in memory. Instead, we open the data temporarily, allowing us to read the data sequentially without processing the entire file. This approach is especially recommended when <em>we don't need all the data contained in the XML file</em>. To do this, we'll add another Python library to our "toolbox": <a target="_blank" href="https://docs.python.org/3/library/io.html"><code>io</code></a>.</p>
<p>Check out the snippet below:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> lxml <span class="hljs-keyword">import</span> etree 
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
<span class="hljs-keyword">import</span> io

url = <span class="hljs-string">'https://github.com/cdisc-org/DataExchange-ODM/raw/main/examples/Demographics_RACE/Demographics_RACE_check_all_that_apply.xml'</span>
response = requests.get(url)
tree = response.content

tree = io.BytesIO(tree)
</code></pre>
<p>Notice that after storing the HTTP request content in the <code>tree</code> variable using <code>requests</code>, the next step is transforming this content using the <a target="_blank" href="https://www.digitalocean.com/community/tutorials/python-io-bytesio-stringio"><code>io.BytesIO()</code></a> function. But what exactly are these things?</p>
<p>The <code>io</code> library, which is part of Python's Standard Library, handles raw data in the simplest way possible and temporarily. This means that when we read the content of the request stored in <code>tree</code>, we only read the content without turning it into a much more complex and heavy ODM tree. In other words, the <code>io.BytesIO()</code> function <em>only opens the file</em> and keeps it in a temporary memory space (a <a target="_blank" href="https://sematext.com/glossary/buffer-vs-cache/"><em>buffer</em></a>) so it can be accessed while the code is running, through a sequence of bytes, as illustrated in the diagram below.</p>
<p><img src="https://mermaid.live/edit#pako:eNptkctuwjAQRX_FMttkQ7rBlSoRsSEUdVF2pIshHhMLPyI_2kaIf6-T0Daq6tlcXx9fWzNX2liOlNGzg64lh7I2JC0fT5NR9gH99mVyh1UdDzaAIut3kApOCsketXX92wwhef5EdsdnaRDcGEHKKAS6GfSrfOhTSkWEVIotxGqozAdnL8gWRVH8JXd3kq_Ekv9DouG1mWSjwPsNCqLHP5bKNpfvdx6Gmt--6_xD8tCyZff5OAsh66yapwxHNKManQbJU_-ug1PT0KLGmrIkDcbgQNW0NreEQgz2tTcNZcFFzKiz8dxSJkD5tIsdh4AbCant-sdFLoN1-2lC46BuXyIMiKk" alt="](https://mermaid.ink/img/pako:eNptkctuwjAQRX_FMttkQ7rBlSoRsSEUdVF2pIshHhMLPyI_2kaIf6-T0Daq6tlcXx9fWzNX2liOlNGzg64lh7I2JC0fT5NR9gH99mVyh1UdDzaAIut3kApOCsketXX92wwhef5EdsdnaRDcGEHKKAS6GfSrfOhTSkWEVIotxGqozAdnL8gWRVH8JXd3kq_Ekv9DouG1mWSjwPsNCqLHP5bKNpfvdx6Gmt--6_xD8tCyZff5OAsh66yapwxHNKManQbJU_-ug1PT0KLGmrIkDcbgQNW0NreEQgz2tTcNZcFFzKiz8dxSJkD5tIsdh4AbCant-sdFLoN1-2lC46BuXyIMiKk?type=png align=&quot;left&quot;)" /></p>
<p>From this point, we can explore the data contained in the <code>tree</code> variable using another method available in <code>lxml.etree</code>, the <a target="_blank" href="https://lxml.de/api/lxml.etree.iterparse-class.html"><code>etree.iterparse</code></a>.</p>
<pre><code class="lang-python"><span class="hljs-keyword">for</span> _, element <span class="hljs-keyword">in</span> etree.iterparse(io.BytesIO(den_xml2)): <span class="hljs-comment">#DICA: Como o io.BytesIO(den_xml2) se trata de uma sequência temporária de caracteres, é mais interessante colocá-lo dentro da iteração em vez de tentar armazená-lo numa variável.</span>
    ...
</code></pre>
<p>From here, it's possible to extract the data in a similar way to the method we used in the previous post.</p>
<h2 id="heading-but-whats-the-difference">But what's the difference?</h2>
<p>You might be wondering what the actual difference is once the suggested changes are applied. It's possible to conduct various performance tests considering execution time and memory usage; but to summarize, look at the graph below, which shows relatively how much memory is used by each function, <code>etree.XML()</code> and <code>io.BytesIO()</code>:</p>
<p><img src="https://i.ibb.co/vHhmk9k/859cad0e-3614-424c-8d7e-09296f0f4db9.png" alt /></p>
<p>Notice that the graph divides between the raw data and the parsed ODM tree (remember the previous diagrams?); since <code>io.BytesIO()</code> only stores the raw data without needing to parse it to access the content, it only uses the space necessary for the bytes of that data to be available. On the other hand, the <code>etree</code> function, besides storing the raw data, has to keep the entire ODM tree available, thus needing more memory. This characteristic is crucial when dealing with XML files that exceed 1GB in size, for example; if we don't have enough memory to hold all the data from the file, we will certainly have numerous problems extracting what we want. Not to mention performance: the greater the memory requirement, the longer it takes to process everything as a result.</p>
<p>In the end, regardless of the size of the XML "monster" you have to deal with, it's still possible to do everything you need in an easier and less painful way using Python. It's up to us now to decide which method best suits each case and continue studying the tools and concepts discussed so far. So, the next time a huge obstacle appears in your path, you can take a moment to breathe, assess, and choose the best tool, so that obstacle becomes a simpler and—why not?—more enjoyable part of the journey.</p>
]]></content:encoded></item><item><title><![CDATA[XML na Prática (2): Fazendo (muito) mais com menos]]></title><description><![CDATA[No último post, vimos como lidar com arquivos ODM-XML usando algumas bibliotecas Python para tanto, fazendo o processo menos temeroso e mais simples.
## Lembra dessas bibliotecas? ##
import requests
from lxml import etree #Neste caso, usamos a API da...]]></description><link>https://blog.matheusyuri.pro/xml-na-pratica-2</link><guid isPermaLink="true">https://blog.matheusyuri.pro/xml-na-pratica-2</guid><category><![CDATA[Python]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[xml]]></category><category><![CDATA[data structures]]></category><category><![CDATA[CDISC]]></category><category><![CDATA[data]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Sun, 03 Nov 2024 11:58:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730634953807/f06ca6ff-ba4d-4ce8-a2c9-4baf5b6da74a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>No <a target="_blank" href="https://blog.matheusyuri.pro/xml-na-pratica">último post</a>, vimos como lidar com arquivos ODM-XML usando algumas bibliotecas Python para tanto, fazendo o processo menos temeroso e mais simples.</p>
<pre><code class="lang-python"><span class="hljs-comment">## Lembra dessas bibliotecas? ##</span>
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> lxml <span class="hljs-keyword">import</span> etree <span class="hljs-comment">#Neste caso, usamos a API da biblioteca 'ElementTree' que está disponível na biblioteca 'lxml'</span>
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
</code></pre>
<p>Essas bibliotecas (especialmente o <code>pandas</code> e o <code>lxml.etree</code>) foram pensados para otimizar a construção e manipulação de conjuntos de dados contidos em um documento XML. No entanto, é possível que encontremos alguns empecilhos no caminho, que não foram abordados no artigo anterior. Aqui estão alguns:</p>
<ul>
<li><p><strong>O documento XML é enorme</strong>: Anteriormente, utilizamos um arquivo cujo tamanho é pequeno; sabemos que, na vida real, as coisas podem muito bem não vir assim. É possível que caia em nossas mãos um arquivo com 1GB de tamanho para mais;</p>
</li>
<li><p><strong>Você não precisa de todos os dados contidos no arquivo</strong>: Para poder manipular um documento XML, bibliotecas como <code>lxml</code> e <code>ElementTree</code> precisam, pela própria natureza desse tipo de arquivo, ler e interpretar um XML do início ao fim. Por razões como o problema já mencionado acima, isso custa tempo e memória, afetando a performance do seu <em>script</em> em Python.</p>
</li>
<li><p><strong>Você não tem à disposição uma máquina robusta</strong>: Os dois problemas acima são muito mais difíceis de resolver quando temos uma máquina mais limitada. Usar plataformas como o <a target="_blank" href="https://colab.research.google.com/">Google Colab</a> podem ser uma alternativa de contorno a isso, mas nem sempre podemos lançar mão desse recurso.</p>
</li>
</ul>
<p>A partir disso, você pode pensar algo como “voltei à estaca zero; como é que eu vou conseguir manipular esse bendito XML, e conseguir os dados de que preciso? Será que terei de ir atrás de outra alternativa senão o Python?”</p>
<p>O objetivo desse artigo é mostrar que ainda não é hora de desistir do Python. Mudando algumas coisas no código, você ganhará, com certeza, mais uma chance de enfrentar os “monstros” do XML, e finalmente conseguir extrair os dados e informações tão esperados.</p>
<h2 id="heading-conhecendo-o-obstaculo">Conhecendo o obstáculo</h2>
<p>Para começar, debruçemo-nos em algumas das primeiras linhas de código que estamos utilizando:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> lxml <span class="hljs-keyword">import</span> etree
<span class="hljs-keyword">import</span> requests

url = <span class="hljs-string">'https://github.com/cdisc-org/DataExchange-ODM/raw/main/examples/Demographics_RACE/Demographics_RACE_check_all_that_apply.xml'</span> <span class="hljs-comment">#Fonte do arquivo .xml que estamos utilizando</span>
response = requests.get(url) <span class="hljs-comment">#Requisição HTTP</span>

tree = response.content <span class="hljs-comment">#O conteúdo da requisição</span>
</code></pre>
<p>Esse bloco de código, como é visto acima, faz três coisas: <strong>1)</strong> Armazena uma <code>string</code> de um endereço URL do GitHub; <strong>2)</strong> Faz uma requisição a esse URL via (<code>requests</code>)[https://requests.readthedocs.io/] para obter o conteúdo do mesmo; e <strong>3)</strong> Armazena o conteúdo da requisição em uma variável (i.e., o arquivo XML do qual extrairemos os dados).</p>
<p>O próximo passo é transformar o conteúdo da variável <code>tree</code> em algo que pode ser lido e explorado pelo <a target="_blank" href="https://lxml.de/"><code>lxml</code></a>, usando a função <code>XML</code>. Assim:</p>
<pre><code class="lang-python">tree = etree.XML(tree, etree.XMLParser(remove_comments=<span class="hljs-literal">True</span>))
</code></pre>
<pre><code class="lang-python">print(tree)
&lt;Element {http://www.cdisc.org/ns/odm/v2<span class="hljs-number">.0</span>}ODM at <span class="hljs-number">0x145a22f7a80</span>&gt;
</code></pre>
<p>O processo de <a target="_blank" href="https://pymotw.com/3/xml.etree.ElementTree/parse.html"><em>parsing</em></a>, que é o processo aqui realizado pelo <code>lxml.etree</code>, consiste em transformar o conteúdo que foi extraído da URL do GitHub em uma árvore ODM com todos os seus elementos. Com isso, podemos explorar o conteúdo de todo o documento XML de forma completa, uma vez que a árvore de elementos estará na memória do computador, pronta para ser utilizada...</p>
<p>... e é aí que pode estar o problema.</p>
<h2 id="heading-entendendo-o-tamanho-do-problema">Entendendo o tamanho do problema</h2>
<p>Como dito anteriormente, o exemplo que estamos utilizando pode ser considerado pequeno, nos mais variados sentidos. Além do tamanho, podemos assumir que a árvore ODM que é resultado do <em>parsing</em> também não é muito grande. Transferindo o exemplo para o seu computador e executando o <em>script</em> inteiro, é possível que o processamento seja rápido e não ocupe tanta memória.</p>
<p>Para casos mais próximos da vida real, nem sempre é assim. Exemplificando através de uma experiência pessoal, já me encontrei na situação de ter de lidar com arquivos XML que, uma vez transformados em DataFrames do pandas, possuíam <strong>mais de 8 milhões de linhas</strong>. Para se ter uma ideia, uma planilha do Excel possui um limite de linhas de um pouco mais de 1 milhão. Um verdadeiro "monstro".</p>
<p>Acontece que, para que a árvore ODM possa ser utilizada através de um <code>parse</code> do <code>lxml</code>, ela precisa ser totalmente "destrinchada", precisando alocar na memória, além do nó raiz (que pode ser visto, neste caso, usando o atributo <code>tree.tag</code> no <code>lxml</code>), os nós filhos, ou <em>children</em>, de toda a estrutura. Essa alocação toda não só gera toda uma complexidade da coisa, mas também pode custar muita memória do computador (um exemplo de como isso tudo estaria distribuído na memória é ilustrado no diagrama abaixo).</p>
<p><img src="https://mermaid.ink/img/pako:eNqNk91KwzAUgF8lxNtOcJPBKgjr2v2IVdAhQutF1p6uYWlT0lSdY4_k1R5hL2b6Mw1ubEsucnq-L4eG5KxwwEPAJp4LksVoavkpUiMvZnUCpAC4fHXv63w5-p4LyXYjKEFTLglDNs0znm6_34G9aRpqtW6R5Tm5FIUsBEH2o6txq-ID72G7QU-EfmloUCG7QkPKYo6u9qij0bZG7YoOvb4UdFZInu-xkfdCGBegE6ci44O7ajY5sOsvyuWSgTpyRBkzL6JeOQ11cL4A86LT6fw3rcaEbtSJomPmoDGDQLlHTbsxe70gOG46Z5vDxux2Zyf-c3S2OT7bnJwwIQ39tA53a8BIntsQoQQSLpYW48FidyvX5dSrNHHrg4YyNtvZ541WBPWNO70KNnACIiE0VN2yKkUfyxgS8LGpwhQKKQjzsZ-ulUrUI3pepgE21esHAwtezGNsRoTl6qvIQiLBpkQ1WfKbhZBKLty6H6u2XP8A7UMU8A?type=png" alt="image" /></p>
<h2 id="heading-transformando-o-obstaculo-no-caminho">Transformando o obstáculo no caminho</h2>
<p>A ideia aqui é, em vez de abrir toda a árvore estrutural do XML e armazenar na memória, abrir os dados sem precisar processar o arquivo, de uma forma temporária, onde nós poderemos ler os dados em sequência. Essa abordagem é especialmente recomendada quando <em>não precisamos de todos os dados contidos no arquivo XML</em>. Para tanto, adicionaremos mais uma biblioteca Python em nossa "caixa de ferramentas": <a target="_blank" href="https://docs.python.org/3/library/io.html"><code>io</code></a>.</p>
<p>Observe o <em>snippet</em> abaixo:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> lxml <span class="hljs-keyword">import</span> etree 
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
<span class="hljs-keyword">import</span> io

url = <span class="hljs-string">'https://github.com/cdisc-org/DataExchange-ODM/raw/main/examples/Demographics_RACE/Demographics_RACE_check_all_that_apply.xml'</span>
response = requests.get(url)
tree = response.content

tree = io.BytesIO(tree)
</code></pre>
<p>Perceba que, após armazenar o conteúdo da requisição HTTP na variável <code>tree</code> usando o <code>requests</code>, o passo seguinte é a transformação desse conteúdo usando a função <a target="_blank" href="https://www.digitalocean.com/community/tutorials/python-io-bytesio-stringio"><code>io.BytesIO()</code></a>. Mas, afinal, o que são essas coisas?</p>
<p>A biblioteca <code>io</code>, que compõe a Biblioteca Padrão do Python, vem lidar com os dados brutos da maneira mais simples possível, e de forma temporária. Isso quer dizer que, ao lermos o conteúdo da requisição que foi armazenada em <code>tree</code>, faremos apenas uma leitura do conteúdo, sem torná-lo uma árvore ODM bem mais complexa e pesada. Ou seja, a função <code>io.BytesIO()</code> <em>somente abre o arquivo</em>, e o deixa em um espaço temporário da memória (um <a target="_blank" href="https://napoleon.com.br/glossario/o-que-e-buffer-memory"><em>buffer</em></a>) para que seja possível acessá-lo enquanto o código é executado, através de uma sequência de bytes, conforme ilustrado no diagrama abaixo.</p>
<p><img src="https://mermaid.ink/img/pako:eNptkU1OwzAQha9iudtk07KpkZCIsqGlYkF3DYshHjdW_RP5B4iqHokVR-jFcHCBCDEjWc9Pn5-lmSNtLUfK6N5B35Ft1RiSysfnbFRDQH_3kN2xVrsN6vOHk0C2NoAitfS9Nef3F1RPE4yU5Q1Z76ooBDpyLw2CIxxz4AT8VT4MCtNDIZViM7Ecu_DB2QOy2WKx-EuuLyRfijn_h0TDs8hnq8D7GgXRqK0bKmXbw_dfV2NPEy66fJU8dGzev11PQshtsZqm0IJqdBokT3M8jmBDQ4caG8qSNBiDA9XQxpwSCjHYx8G0lAUXsaDOxn1HmQDl0y32HALWEtL49Y-LXAbrNnlTXws7fQKEgox2?type=png" alt="image" /></p>
<p>A partir disso, podemos realizar uma exploração dos dados contidos na variável <code>tree</code> através de um outro método presente no <code>lxml.etree</code>, o <a target="_blank" href="https://lxml.de/api/lxml.etree.iterparse-class.html"><code>etree.iterparse</code></a>.</p>
<pre><code class="lang-python"><span class="hljs-keyword">for</span> _, element <span class="hljs-keyword">in</span> etree.iterparse(io.BytesIO(den_xml2)): <span class="hljs-comment">#DICA: Como o io.BytesIO(den_xml2) se trata de uma sequência temporária de caracteres, é mais interessante colocá-lo dentro da iteração em vez de tentar armazená-lo numa variável.</span>
    ...
</code></pre>
<p>A partir daqui, é possível extrair os dados de maneira semelhante ao método que utilizamos no post anterior.</p>
<h2 id="heading-mas-qual-e-a-diferenca">Mas qual é a diferença?</h2>
<p>Você pode estar se perguntando sobre qual é a diferença factual vista uma vez aplicada as mudanças sugeridas. É possível fazer vários testes de performance considerando o tempo de execução e a quantidade de memória utilizada; mas, para resumir, observe o gráfico a seguir, que mostra de maneira relativa o quanto de memória é ocupada por cada função, <code>etree.XML()</code> e <code>io.BytesIO()</code>:</p>
<p><img src="https://i.postimg.cc/85VyCYyr/a503f45f-0ffc-4a2c-b5f3-f20a08034fb1.png" alt="image" /></p>
<p>Perceba que o gráfico faz a divisão entre os dados brutos e a árvore ODM parseada (lembra dos diagramas anteriores?); uma vez que o <code>io.BytesIO()</code> apenas armazena os dados brutos, sem precisar fazer nenhum <em>parsing</em> para acessar o conteúdo, ele ocupa apenas o espaço necessário para que os bytes desses dados estejam disponíveis; já a função do <code>etree</code>, além de armazenar os dados brutos, tem de manter disponível a árvore ODM inteira, assim tendo que ocupar mais memória. Essa característica é decisiva na hora de lidarmos com arquivos XML que rompem a barreira dos 1GB de tamanho, por exemplo; se não temos uma quantidade de memória o suficiente para que caiba todos os dados do arquivo, certamente teremos inúmeros problemas para extrair o que queremos. Isso sem falar na performance: quanto maior a necessidade de memória, mais tempo para processarmos tudo, por consequência.</p>
<p>Ao fim e ao cabo, independentemente do tamanho do "monstro" XML com o qual você terá de lidar, ainda é possível fazer tudo que se precisa de uma maneira mais fácil e menos dolorosa usando o Python. Cabe a nós agora decidirmos qual método se adapta melhor a cada caso, e seguir estudando sobre as ferramentas e conceitos que foram abordados até agora. E assim, da próxima vez que um obstáculo enorme aparecer em seu caminho, você pode parar pra respirar, avaliar e escolher a melhor ferramenta, para que esse obstáculo se torne uma parte mais simples e - por que não? - mais divertida do caminho.</p>
]]></content:encoded></item><item><title><![CDATA[Mastering XML with Python: A Guide to Handling ODM-XML Files]]></title><description><![CDATA[Context
In clinical studies, it's common to work with datasets that can come in various formats, depending on what the chosen EDC system can offer. However, in some situations, it will be necessary to extract a complete dataset, according to what reg...]]></description><link>https://blog.matheusyuri.pro/mastering-xml-with-python-a-guide-to-handling-odm-xml-files</link><guid isPermaLink="true">https://blog.matheusyuri.pro/mastering-xml-with-python-a-guide-to-handling-odm-xml-files</guid><category><![CDATA[xml]]></category><category><![CDATA[xml-parsing]]></category><category><![CDATA[Python]]></category><category><![CDATA[clinical trials]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[data structures]]></category><category><![CDATA[dataanalytics]]></category><category><![CDATA[CDISC]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Sun, 20 Oct 2024 14:27:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729433896298/dc699e11-452c-4cee-8a86-722db7766ca4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-context">Context</h2>
<p>In clinical studies, it's common to work with datasets that can come in various formats, depending on what the chosen <a target="_blank" href="https://en.wikipedia.org/wiki/Electronic_data_capture">EDC</a> system can offer. However, in some situations, it will be necessary to extract a complete dataset, according to what regulatory entities require for the approval submissions of drug and vaccine use, mainly. From that point, there isn't much choice; an XML document will always appear as the most facilitated option. For those used to dealing with all types of data, some effort might be needed to transform it into something that can be used in various analyses. And for those used to dealing only with structured data (like spreadsheets), panic sets in. What now? What to do from there?</p>
<p>In this article, we will explore some of the secrets hidden in an ODM-XML document, as well as how we can uncover these secrets and produce a spreadsheet that makes sense for clinical study data analysis.</p>
<h2 id="heading-why-xml">Why XML?</h2>
<p>In general, <a target="_blank" href="https://aws.amazon.com/what-is/xml/">there are some good reasons to use XML when working with data</a>. For example:</p>
<ul>
<li><p><strong>You can create a file that works with many data manipulation tools</strong>. Since an XML document is a text file, it can be easily transferred between different technologies. Many technologies can read and process XML for this reason (some examples can be found <a target="_blank" href="https://www.researchgate.net/publication/309022617_Comparing_Common_Programming_Languages_to_Parse_Big_XML_File_in_Terms_of_Executing_Time_Memory_Usage_CPU_Consumption_and_Line_Number_on_Two_Platforms">here</a>).</p>
</li>
<li><p><strong>It maintains data integrity</strong>, which is crucial when working with databases. This is achieved by combining metadata and data in a single file, ensuring all resources are available without needing to import other files (we will explore this in more detail throughout the article)<a class="post-section-overview" href="#um"><sup>1</sup></a>.</p>
</li>
<li><p><strong>The organization and categorization of data are more efficient</strong>, making it easier and faster to find specific information within an XML document.</p>
</li>
</ul>
<h2 id="heading-what-is-odm">What is ODM?</h2>
<p><a target="_blank" href="https://www.altexsoft.com/blog/cdisc-standards/">ODM</a> stands for <em>Operational Data Model</em>. According to <a target="_blank" href="https://www.cdisc.org/standards/data-exchange/odm">CDISC</a>, "it is a format that can be used to store and exchange data between data management systems, as well as to store data, metadata, and administrative data related to a clinical study." For some health regulatory entities, like the FDA in the United States <a class="post-section-overview" href="#dois"><sup>2</sup></a> <a class="post-section-overview" href="#tres"><sup>3</sup></a> <a class="post-section-overview" href="#quatro"><sup>4</sup></a> <a class="post-section-overview" href="#cinco"><sup>5</sup></a>, CDISC has suggested this format as the standard for data archiving because of its ability to carry all relevant information for clinical studies in a single interchangeable file when needed.</p>
<p>The ODM model offers an XML model that facilitates the capture of clinical data; from a schema like the one in the figure below, we can divide the XML document into two main parts: the metadata, which provides the definition of the variables to be used, and the actual data, where the clinical study information is stored.</p>
<p><img src="https://www.researchgate.net/profile/Hugo-Leroux/publication/259220016/figure/fig1/AS:297314913669122@1447896807509/Structure-of-CDISC-ODM-XML-schema-adapted-from-ODM-11-documentation-9.png" alt="None" /></p>
<p>The schema of an XML document for clinical data, according to the ODM model established by CDISC. <a class="post-section-overview" href="#seis"><sup>6</sup></a></p>
<p><img src="https://i.ibb.co/PCBCnZG/pone-0199242-g001.png" alt="None" /></p>
<p>Another schema of an XML document for clinical data. <a class="post-section-overview" href="#sete"><sup>7</sup></a></p>
<h2 id="heading-importing-libraries">Importing libraries</h2>
<p>When using Python to extract data from <code>.xml</code> documents, you need to import some libraries. If you use platforms like <a target="_blank" href="https://www.anaconda.com/">Anaconda</a> or <a target="_blank" href="https://winpython.github.io/">WinPython</a>, simply using <code>import</code> might be enough. If you're using a "pure" version of Python, I recommend installing the libraries using <a target="_blank" href="https://en.wikipedia.org/wiki/Pip_\(package_manager\)"><code>pip</code></a> before proceeding with the following steps.</p>
<p>In this article, we will use libraries such as:</p>
<ul>
<li><p><a target="_blank" href="https://requests.readthedocs.io/en/latest/"><code>requests</code></a>, the simplest library for making web page requests (because life is complex enough);</p>
</li>
<li><p><a target="_blank" href="https://lxml.de/"><code>lxml</code></a>, another easy-to-use library for processing XML files;</p>
</li>
<li><p><a target="_blank" href="https://pandas.pydata.org/"><code>pandas</code></a>, the most well-known library for data manipulation and analysis; with it, you can create a spreadsheet with the XML data.</p>
</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> lxml <span class="hljs-keyword">import</span> etree <span class="hljs-comment">#In this case, we are going to use the ElementTree API available in the lxml library.</span>
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
</code></pre>
<h2 id="heading-getting-the-data">Getting the data</h2>
<p>The <code>.xml</code> document we will use comes from a <a target="_blank" href="https://github.com/cdisc-org/DataExchange-ODM">CDISC GitHub repository</a>. To obtain it directly, i.e., without downloading any files, we will use the <code>requests</code> library. The <a target="_blank" href="https://www.w3schools.com/python/ref_requests_get.asp"><code>get</code></a> function of this library makes a request to a GitHub page containing the file and waits for a response from that page, which we are storing in the <code>response</code> variable. If the response is code <code>200</code>, <a target="_blank" href="https://www.geeksforgeeks.org/response-methods-python-requests/">it means the request was successful</a>.</p>
<pre><code class="lang-python">url = <span class="hljs-string">'https://github.com/cdisc-org/DataExchange-ODM/raw/main/examples/Demographics_RACE/Demographics_RACE_check_all_that_apply.xml'</span>
response = requests.get(url)
print(response)
</code></pre>
<pre><code class="lang-txt">&lt;Response [200]&gt;
</code></pre>
<p>From this response, we will use the <a target="_blank" href="https://www.geeksforgeeks.org/response-content-python-requests/"><code>content</code></a> object to actually get the XML that will be explored. The content will be available in the <code>tree</code> variable, as shown in the code below:</p>
<pre><code class="lang-python">tree = response.content
</code></pre>
<p>The variable <code>tree</code> will be with us throughout the entire process of building the spreadsheet from the information we have.</p>
<h2 id="heading-transforming-and-checking-the-xml-structure">Transforming and Checking the XML Structure</h2>
<p>After extracting the content from the GitHub page, you can observe the structure of the XML that will be explored when the content is transformed into a readable variable. This is important for locating the tags, attributes, and values where the relevant data is found.</p>
<p>From here, we begin using another library we imported: <code>lxml</code>, which is dedicated to obtaining the XML elements mentioned earlier. We will store the entire XML in the variable <code>tree</code>, where the content from the GitHub page will be passed along with the type of parser (the transformer) that will be used. The variable <code>tree2</code>, in this case, serves to allow us to actually observe the "skeleton" of the XML.</p>
<pre><code class="lang-python">tree = etree.XML(tree, etree.XMLParser(remove_comments=<span class="hljs-literal">True</span>))
tree2 = etree.tostring(tree, pretty_print = <span class="hljs-literal">True</span>, encoding = str)
print(tree2)
</code></pre>
<pre><code class="lang-txt">    &lt;ODM xmlns="http://www.cdisc.org/ns/odm/v2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlink="http://www.w3.org/1999/xlink" CreationDateTime="2020-07-06T10:20:15+01:00" FileOID="DEMOGRAPHICS_EXAMPLE" FileType="Snapshot" Granularity="Metadata" ODMVersion="2.0" SourceSystem="XML4Pharma CDISC ODM Study Designer" SourceSystemVersion="2015-R1"&gt;
       &lt;Study OID="ST.DEMOGRAPHICS_EXAMPLE" StudyName="Study with Demographics example" ProtocolName="MyStudy"&gt;
          &lt;Description&gt;&lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Demographics example with Race, with "check all that apply"&lt;/TranslatedText&gt;&lt;/Description&gt;
          &lt;MetaDataVersion Name="Version 1" OID="MV.1.0"&gt;
             &lt;Description&gt;&lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Version 1&lt;/TranslatedText&gt;&lt;/Description&gt;
             &lt;StudyEventDef Name="Screening visit with demographics" OID="SE.SCREENING" Repeating="No" Type="Scheduled"&gt;
                &lt;ItemGroupRef ItemGroupOID="FO.DEMOGRAPHICS" Mandatory="Yes"/&gt;
             &lt;/StudyEventDef&gt;
             &lt;ItemGroupDef Name="Demographics form" OID="FO.DEMOGRAPHICS" Type="Form" Repeating="No"&gt;
                &lt;ItemGroupRef ItemGroupOID="IG.DEMOGRAPHICS" Mandatory="Yes"/&gt;
             &lt;/ItemGroupDef&gt;
             &lt;ItemGroupDef Name="Demographics" OID="IG.DEMOGRAPHICS" Type="Section" Repeating="No"&gt;
                &lt;ItemRef ItemOID="IT.DOB" Mandatory="Yes"/&gt;
                &lt;ItemRef ItemOID="IT.SEX" Mandatory="Yes"/&gt;
                &lt;ItemRef ItemOID="IT.ETHNIC" Mandatory="Yes"/&gt;


                &lt;ItemGroupRef ItemGroupOID="IG.RACE" Mandatory="Yes"/&gt;
             &lt;/ItemGroupDef&gt;

             ...

             &lt;CodeList DataType="integer" Name="Sex" OID="CL.SEX"&gt;
                &lt;CodeListItem CodedValue="1"&gt;
                   &lt;Decode&gt;
                      &lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Male&lt;/TranslatedText&gt;
                   &lt;/Decode&gt;
                &lt;/CodeListItem&gt;
                &lt;CodeListItem CodedValue="2"&gt;
                   &lt;Decode&gt;
                      &lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Female&lt;/TranslatedText&gt;
                   &lt;/Decode&gt;
                &lt;/CodeListItem&gt;
             &lt;/CodeList&gt;
             &lt;CodeList DataType="integer" Name="Ethnicity" OID="CL.ETHNIC"&gt;
                &lt;CodeListItem CodedValue="1"&gt;
                   &lt;Decode&gt;
                      &lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Hispanic&lt;/TranslatedText&gt;
                   &lt;/Decode&gt;
                &lt;/CodeListItem&gt;
                &lt;CodeListItem CodedValue="2"&gt;
                   &lt;Decode&gt;
                      &lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Non-hispanic&lt;/TranslatedText&gt;
                   &lt;/Decode&gt;
                &lt;/CodeListItem&gt;
             &lt;/CodeList&gt;

             ...

          &lt;/MetaDataVersion&gt;
       &lt;/Study&gt;

       &lt;ClinicalData StudyOID="ST.DEMOGRAPHICS_EXAMPLE" MetaDataVersionOID="MV.1.0"&gt;

          &lt;SubjectData SubjectKey="001"&gt;
             &lt;StudyEventData StudyEventOID="SE.SCREENING"&gt;
                &lt;ItemGroupData ItemGroupOID="FO.DEMOGRAPHICS"&gt;
                   &lt;ItemGroupData ItemGroupOID="IG.DEMOGRAPHICS"&gt;
                      &lt;ItemData ItemOID="IT.DOB"&gt;&lt;Value&gt;1957-05-07&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.SEX"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.ETHNIC"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;

                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="1"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;

                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="2"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;true&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="3"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;3&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="4"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;4&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;4&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="5"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;5&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="6"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;99&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                   &lt;/ItemGroupData&gt;
                &lt;/ItemGroupData&gt;
             &lt;/StudyEventData&gt;
          &lt;/SubjectData&gt;

          ...

          &lt;SubjectData SubjectKey="003"&gt;
             &lt;StudyEventData StudyEventOID="SE.SCREENING"&gt;
                &lt;ItemGroupData ItemGroupOID="FO.DEMOGRAPHICS"&gt;
                   &lt;ItemGroupData ItemGroupOID="IG.DEMOGRAPHICS"&gt;
                      &lt;ItemData ItemOID="IT.DOB"&gt;&lt;Value&gt;1961-06-09&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.SEX"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.ETHNIC"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;

                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="1"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="2"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="3"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;3&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="4"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;4&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="5"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;5&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="6"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;99&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;true&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACEOTH"&gt;&lt;Value&gt;Native Amazonian&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                   &lt;/ItemGroupData&gt;
                &lt;/ItemGroupData&gt;
             &lt;/StudyEventData&gt;
          &lt;/SubjectData&gt;
       &lt;/ClinicalData&gt;
    &lt;/ODM&gt;
</code></pre>
<h2 id="heading-checking-the-namespaces">Checking the namespaces</h2>
<p>When exploring an XML, it's essential to be aware of the <a target="_blank" href="https://en.wikipedia.org/wiki/XML_namespace">namespaces</a> it contains. Namespaces can provide a unique identification for each component tag. The use of namespaces is recommended by the W3C and is very necessary when we have tags or attributes with similar names but associated with different elements or tags. To see which namespaces appear in the XML document, use the <a target="_blank" href="https://lxml.de/4.3/api/lxml.etree._Element-class.html"><code>nsmap</code></a> object, as shown below:</p>
<pre><code class="lang-python">ns = tree.nsmap
print(ns)
</code></pre>
<pre><code class="lang-txt">{None: 'http://www.cdisc.org/ns/odm/v2.0', 'xs': 'http://www.w3.org/2001/XMLSchema', 'xlink': 'http://www.w3.org/1999/xlink'}
</code></pre>
<h2 id="heading-checking-tags">Checking tags</h2>
<p>Now that we know about the namespaces, we can analyze what the names of the <em>tags</em> are. These names will allow us to extract the data of interest later on.</p>
<pre><code class="lang-python">elements = []
<span class="hljs-keyword">for</span> elem <span class="hljs-keyword">in</span> tree.iter():
    elements.append(elem.tag)

elements = list(set(elements))
print(elements)
</code></pre>
<pre><code class="lang-txt">['{http://www.cdisc.org/ns/odm/v2.0}TranslatedText', '{http://www.cdisc.org/ns/odm/v2.0}Description', '{http://www.cdisc.org/ns/odm/v2.0}ItemGroupDef', '{http://www.cdisc.org/ns/odm/v2.0}Decode', '{http://www.cdisc.org/ns/odm/v2.0}ClinicalData', '{http://www.cdisc.org/ns/odm/v2.0}ODM', '{http://www.cdisc.org/ns/odm/v2.0}ItemGroupData', '{http://www.cdisc.org/ns/odm/v2.0}ItemRef', '{http://www.cdisc.org/ns/odm/v2.0}Question', '{http://www.cdisc.org/ns/odm/v2.0}CodeListItem', '{http://www.cdisc.org/ns/odm/v2.0}SubjectData', '{http://www.cdisc.org/ns/odm/v2.0}ItemGroupRef', '{http://www.cdisc.org/ns/odm/v2.0}MetaDataVersion', '{http://www.cdisc.org/ns/odm/v2.0}StudyEventData', '{http://www.cdisc.org/ns/odm/v2.0}Study', '{http://www.cdisc.org/ns/odm/v2.0}Value', '{http://www.cdisc.org/ns/odm/v2.0}CodeListRef', '{http://www.cdisc.org/ns/odm/v2.0}StudyEventDef', '{http://www.cdisc.org/ns/odm/v2.0}ItemDef', '{http://www.cdisc.org/ns/odm/v2.0}ItemData', '{http://www.cdisc.org/ns/odm/v2.0}CodeList']
</code></pre>
<h2 id="heading-extracting-the-first-attributes">Extracting the first attributes</h2>
<p>Knowing how the XML file is structured and which tags are present, it's possible to select where the data of interest is located. The next step is to analyze what's inside the tags. This content is called attributes. Attributes are internal parts of the tags that follow a pattern <code>'Name="Value"'</code>. Notice the attribute <code>'ItemOID'</code> at the end of the first line; it is accompanied by a value <code>"IT.DOB"</code>. This is the pattern used and recommended by the W3C when it comes to attributes. <a class="post-section-overview" href="#oito"><sup>8</sup></a></p>
<pre><code class="lang-python">print(etree.tostring(tree.find(<span class="hljs-string">'.//ItemData'</span>, ns), pretty_print = <span class="hljs-literal">True</span>, encoding = str))
</code></pre>
<pre><code class="lang-txt">    &lt;ItemData xmlns="http://www.cdisc.org/ns/odm/v2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlink="http://www.w3.org/1999/xlink" ItemOID="IT.DOB"&gt;
      &lt;Value&gt;1957-05-07&lt;/Value&gt;
    &lt;/ItemData&gt;
</code></pre>
<p>To access the attributes of a specific tag, you can use two functions from <code>lxml</code>, depending on the situation: <a target="_blank" href="https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.find"><code>find</code></a> and <a target="_blank" href="https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.findall"><code>findall</code></a>. The first one is used to retrieve only the first occurrence of a tag in the XML file, while the other returns all occurrences of tags with the mentioned name.</p>
<pre><code class="lang-python">tree.find(<span class="hljs-string">'.//ClinicalData'</span>, ns) <span class="hljs-comment">#Only the first occurence of the tag 'ClinicalData'.</span>
</code></pre>
<pre><code class="lang-txt">&lt;Element {http://www.cdisc.org/ns/odm/v2.0}ClinicalData at 0x21052103e80&gt;
</code></pre>
<pre><code class="lang-python">tree.findall(<span class="hljs-string">'.//SubjectData'</span>, ns) <span class="hljs-comment">#Todas as ocorrências da tag SubjectData</span>
</code></pre>
<pre><code class="lang-txt">[&lt;Element {http://www.cdisc.org/ns/odm/v2.0}SubjectData at 0x21052102e00&gt;,
&lt;Element {http://www.cdisc.org/ns/odm/v2.0}SubjectData at 0x21052108540&gt;,
&lt;Element {http://www.cdisc.org/ns/odm/v2.0}SubjectData at 0x21052108840&gt;]
</code></pre>
<p>Notice that when we use these functions, the return is an object of the class <a target="_blank" href="https://docs.python.org/3/library/xml.etree.elementtree.html#element-objects"><code>Element</code></a>; however, this is not exactly what we are looking for. To find out what the tags and their attributes really are, we can use two objects with suggestive names: <code>attrib</code> and <code>tag</code>. For attributes, the results return as a dictionary, where the key is the attribute's name, and the value is the attribute's value. The <code>tag</code> function, on the other hand, returns the names of the mentioned tags.</p>
<pre><code class="lang-python">tree.find(<span class="hljs-string">'.//ClinicalData'</span>, ns).attrib <span class="hljs-comment">#The attributes of the tag 'ClinicalData' (the only tag, in this case).</span>
</code></pre>
<pre><code class="lang-txt">{'StudyOID': 'ST.DEMOGRAPHICS_EXAMPLE', 'MetaDataVersionOID': 'MV.1.0'}
</code></pre>
<pre><code class="lang-python"><span class="hljs-keyword">for</span> subject <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//SubjectData'</span>, ns):
    subj = subject.attrib <span class="hljs-comment">#Attributes of each 'SubjectData' tag.</span>
    print(subj)
</code></pre>
<pre><code class="lang-txt">{'SubjectKey': '001'}
{'SubjectKey': '002'}
{'SubjectKey': '003'}
</code></pre>
<pre><code class="lang-python">tree.find(<span class="hljs-string">'.//SubjectData'</span>, ns).tag <span class="hljs-comment">#Name of the tag.</span>
</code></pre>
<pre><code class="lang-txt">'{http://www.cdisc.org/ns/odm/v2.0}SubjectData'
</code></pre>
<pre><code class="lang-python"><span class="hljs-keyword">for</span> subject <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//SubjectData'</span>, ns):
    <span class="hljs-keyword">for</span> eve <span class="hljs-keyword">in</span> subject:
        print(eve.attrib) <span class="hljs-comment">#All attributes of the 'SubjectData' tag.</span>
</code></pre>
<pre><code class="lang-txt">{'StudyEventOID': 'SE.SCREENING'}
{'StudyEventOID': 'SE.SCREENING'}
{'StudyEventOID': 'SE.SCREENING'}
</code></pre>
<pre><code class="lang-python"><span class="hljs-keyword">for</span> subject <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//SubjectData'</span>, ns):
    <span class="hljs-keyword">for</span> event <span class="hljs-keyword">in</span> subject:
        <span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> event:
            ite = item.attrib
            print(ite) <span class="hljs-comment">#All the attributes of 'ItemGroupOID'</span>
</code></pre>
<pre><code class="lang-txt">{'ItemGroupOID': 'FO.DEMOGRAPHICS'}
{'ItemGroupOID': 'FO.DEMOGRAPHICS'}
{'ItemGroupOID': 'FO.DEMOGRAPHICS'}
</code></pre>
<p>If you want to extract only the value of a specific attribute, just select the attribute using its name in brackets, similar to how you find the value of a specific key stored in a dictionary:</p>
<pre><code class="lang-python">print(subj[<span class="hljs-string">'SubjectKey'</span>]) <span class="hljs-comment">#Value of the last 'SubjectKey' attribute in the 'SubjectData' tag.</span>
</code></pre>
<pre><code class="lang-txt">003
</code></pre>
<h2 id="heading-checking-the-xml-structure-for-just-one-subject">Checking the XML structure for just one subject</h2>
<p>We have already seen how to filter one or more tags by their names and discover their attributes and values. If it is interesting or necessary to analyze the XML structure of just one tag occurrence (in this case, an individual) more deeply, you can use the <code>find</code> function, which we already know. With the code below, we can check the XML structure for the first subject.</p>
<pre><code class="lang-python">print(etree.tostring(tree.find(<span class="hljs-string">'.//SubjectData'</span>, ns), pretty_print = <span class="hljs-literal">True</span>, encoding = str))
</code></pre>
<pre><code class="lang-txt">    &lt;SubjectData xmlns="http://www.cdisc.org/ns/odm/v2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlink="http://www.w3.org/1999/xlink" SubjectKey="001"&gt;
             &lt;StudyEventData StudyEventOID="SE.SCREENING"&gt;
                &lt;ItemGroupData ItemGroupOID="FO.DEMOGRAPHICS"&gt;
                   &lt;ItemGroupData ItemGroupOID="IG.DEMOGRAPHICS"&gt;
                      &lt;ItemData ItemOID="IT.DOB"&gt;&lt;Value&gt;1957-05-07&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.SEX"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.ETHNIC"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;

                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="1"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;

                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="2"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;true&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="3"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;3&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="4"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;4&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;4&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="5"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;5&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="6"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;99&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                   &lt;/ItemGroupData&gt;
                &lt;/ItemGroupData&gt;
             &lt;/StudyEventData&gt;
          &lt;/SubjectData&gt;
</code></pre>
<p>Now, if we want to filter the tags and attributes related to a specific subject, we need to mention the <code>SubjectKey</code> attribute and specify the subject's value (in this case, '002'), as shown in the code below:</p>
<pre><code class="lang-python">print(etree.tostring(tree.find(<span class="hljs-string">'.//SubjectData[@SubjectKey="002"]'</span>, ns), pretty_print = <span class="hljs-literal">True</span>, encoding = str))
</code></pre>
<pre><code class="lang-txt">    &lt;SubjectData xmlns="http://www.cdisc.org/ns/odm/v2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlink="http://www.w3.org/1999/xlink" SubjectKey="002"&gt;
             &lt;StudyEventData StudyEventOID="SE.SCREENING"&gt;
                &lt;ItemGroupData ItemGroupOID="FO.DEMOGRAPHICS"&gt;
                   &lt;ItemGroupData ItemGroupOID="IG.DEMOGRAPHICS"&gt;
                      &lt;ItemData ItemOID="IT.DOB"&gt;&lt;Value&gt;1975-01-31&amp;gt;&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.SEX"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.ETHNIC"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;

                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="1"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="2"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="3"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;3&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;true&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="4"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;4&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="5"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;5&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="6"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;99&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                   &lt;/ItemGroupData&gt;
                &lt;/ItemGroupData&gt;
             &lt;/StudyEventData&gt;
          &lt;/SubjectData&gt;
</code></pre>
<h2 id="heading-looking-for-data-from-just-one-tag">Looking for data from just one tag</h2>
<p>Just as we can analyze how an entire XML document is structured, it is possible to specify a tag and separate its structure, allowing us to examine how the tag itself is arranged, as well as the tags connected to it.</p>
<pre><code class="lang-python">print(etree.tostring(tree.find(<span class="hljs-string">'.//ItemData'</span>, ns), pretty_print = <span class="hljs-literal">True</span>, encoding = str))
</code></pre>
<pre><code class="lang-txt">    &lt;ItemData xmlns="http://www.cdisc.org/ns/odm/v2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlink="http://www.w3.org/1999/xlink" ItemOID="IT.DOB"&gt;
      &lt;Value&gt;1957-05-07&lt;/Value&gt;
    &lt;/ItemData&gt;
</code></pre>
<p>Now, check the <code>Value</code> tag: it has a value we want to extract, but it's not in an attribute; it's text between the tags. To access the content between the opening and closing tags, we can use the <code>text</code> class from <code>lxml</code>.</p>
<pre><code class="lang-python">tree.find(<span class="hljs-string">'.//Value'</span>, ns).text
</code></pre>
<pre><code class="lang-txt">'1957-05-07'
</code></pre>
<p>We can do the same with the tag name, this time using the <code>tag</code> class.</p>
<pre><code class="lang-python">tree.find(<span class="hljs-string">'.//Value'</span>, ns).tag
</code></pre>
<pre><code class="lang-txt">'{http://www.cdisc.org/ns/odm/v2.0}Value'
</code></pre>
<h2 id="heading-making-spreadsheets">Making spreadsheets</h2>
<p>Now that we know some basic points about XML and how to manipulate them using Python libraries, we can move on to the next phase: creating spreadsheets (or producing DataFrames). But before we do that, with what we've already learned, we'll organize a data extraction scheme using <code>lxml</code>.</p>
<p>Our goal here is to create a DataFrame containing the <em>date of birth</em>, <em>gender</em>, and <em>ethnicity</em> data for each individual recorded in the XML document. To achieve this, we'll adopt a strategy of establishing a <code>for</code> loop, so that with each iteration, we can extract the data associated with the <code>SubjectData</code> tag and its descendants. After completing the iterations, we'll store the data in a <code>results</code> list, whose outcome is shown below. This is an interesting method because the extracted values are organized into three distinct groups, which will become the columns of our future DataFrame.</p>
<pre><code class="lang-python">results = []
<span class="hljs-keyword">for</span> ide <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//SubjectData'</span>, ns):
    <span class="hljs-keyword">for</span> subj <span class="hljs-keyword">in</span> ide.findall(<span class="hljs-string">'.//StudyEventData/ItemGroupData/ItemGroupData/ItemData'</span>, ns):
            <span class="hljs-keyword">for</span> value <span class="hljs-keyword">in</span> subj:
                results.append([ide.attrib[<span class="hljs-string">'SubjectKey'</span>], subj.attrib[<span class="hljs-string">'ItemOID'</span>], value.text])

results
</code></pre>
<pre><code class="lang-txt">[['001', 'IT.DOB', '1957-05-07'],
['001', 'IT.SEX', '1'],
['001', 'IT.ETHNIC', '2'],
['002', 'IT.DOB', '1975-01-31&gt;'],
['002', 'IT.SEX', '2'],
['002', 'IT.ETHNIC', '2'],
['003', 'IT.DOB', '1961-06-09'],
['003', 'IT.SEX', '2'],
['003', 'IT.ETHNIC', '1']]
</code></pre>
<p>Once the list is created and stored in the <code>results</code> variable, we can easily use <code>pandas</code> to make a DataFrame with the <code>pd.DataFrame</code> function. It's easy because we can use the list we produced directly, without needing more transformations. In this function, we'll pass the list as an argument and specify the names of the columns we want to appear: <code>ID</code>, <code>Variable</code>, <code>Value</code>. It's possible, without any issues, to assign any name to each column.</p>
<pre><code class="lang-python">results = pd.DataFrame(results, columns=[<span class="hljs-string">'ID'</span>, <span class="hljs-string">'Variable'</span>, <span class="hljs-string">'Value'</span>]) 
results
</code></pre>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td>ID</td><td>Variable</td><td>Value</td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td>001</td><td>IT.DOB</td><td>1957-05-07</td></tr>
<tr>
<td>1</td><td>001</td><td><a target="_blank" href="http://IT.SEX">IT.SEX</a></td><td>1</td></tr>
<tr>
<td>2</td><td>001</td><td>IT.ETHNIC</td><td>2</td></tr>
<tr>
<td>3</td><td>002</td><td>IT.DOB</td><td>1975-01-31&gt;</td></tr>
<tr>
<td>4</td><td>002</td><td><a target="_blank" href="http://IT.SEX">IT.SEX</a></td><td>2</td></tr>
<tr>
<td>5</td><td>002</td><td>IT.ETHNIC</td><td>2</td></tr>
<tr>
<td>6</td><td>003</td><td>IT.DOB</td><td>1961-06-09</td></tr>
<tr>
<td>7</td><td>003</td><td><a target="_blank" href="http://IT.SEX">IT.SEX</a></td><td>2</td></tr>
<tr>
<td>8</td><td>003</td><td>IT.ETHNIC</td><td>1</td></tr>
</tbody>
</table>
</div><p>We have a DataFrame, but we need to go a bit further before considering it complete. The main idea here is to have <code>results</code> with only one ID per row, ensuring all data related to that ID is in the same row. Here, we see that we could use the values from the <code>Variable</code> column as column names, and what's in the <code>Value</code> column would be the values for each column by ID.</p>
<p>The good news is that <code>pandas</code> allows us to do this without any problem. What we will perform now is a <em>pivot</em> of the data we have. For this, we can use two functions: <code>pivot</code> and <code>pivot_table</code>, with a slight difference between them. The function chosen here is <code>pivot_table</code>, where we will use <code>results</code> as the data source, the <code>ID</code> column as the temporary index of the DataFrame, the <code>Variable</code> column to name the new columns, and the <code>Value</code> column to provide the values for the columns. Additionally, we need to invoke a function in the <code>aggfunc</code> argument, which serves as a function to perform calculations or organize data in a specific order (the first data to appear, the last, etc.). In this case, we will use the <code>first</code> function because we simply want the first (and only) value to appear in the DataFrame. Finally, we will use <code>reset_index</code>, making <code>ID</code> a manipulable column again.</p>
<pre><code class="lang-python">results = pd.pivot_table(results, index=<span class="hljs-string">'ID'</span>, columns=<span class="hljs-string">'Variable'</span>, values=<span class="hljs-string">'Value'</span>, aggfunc=<span class="hljs-string">'first'</span>).reset_index()
results
</code></pre>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Variable</td><td>ID</td><td>IT.DOB</td><td>IT.ETHNIC</td><td><a target="_blank" href="http://IT.SEX">IT.SEX</a></td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td>001</td><td>1957-05-07</td><td>2</td><td>1</td></tr>
<tr>
<td>1</td><td>002</td><td>1975-01-31&gt;</td><td>2</td><td>2</td></tr>
<tr>
<td>2</td><td>003</td><td>1961-06-09</td><td>1</td><td>2</td></tr>
</tbody>
</table>
</div><p>This way, we are giving a more definitive appearance to our DataFrame. However, notice that the column names, as well as the values in the last two sheets, still do not clearly tell us what information is being shown. By looking more closely at the XML document, we can see that there is a part that provides valuable information to give more meaning to the data we have: the metadata section. This is what we will explore from now on.</p>
<h2 id="heading-searching-for-the-metadata-of-the-xml-document-and-improving-the-spreadsheet">Searching for the metadata of the XML document (and improving the spreadsheet)</h2>
<p>Metadata are the definitions of each variable and value within the XML document. It is interesting, even necessary, to obtain them so we can truly understand what each column and value represents in a DataFrame. In this specific document, the metadata we are interested in are located in the tags named <code>ItemDef</code>, and we can extract them with the block of code illustrated below:</p>
<pre><code class="lang-python"><span class="hljs-keyword">for</span> meta <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//ItemDef'</span>, ns):
    print(meta.attrib)
</code></pre>
<pre><code class="lang-txt">{'DataType': 'date', 'Name': 'Date of birth', 'OID': 'IT.DOB'}
{'DataType': 'integer', 'Length': '1', 'Name': 'Sex', 'OID': 'IT.SEX'}
{'DataType': 'integer', 'Length': '1', 'Name': 'Ethnicity', 'OID': 'IT.ETHNIC'}
{'OID': 'IT.RACE_CODE', 'Name': 'Race code', 'DataType': 'integer', 'Length': '1'}
{'DataType': 'boolean', 'Length': '1', 'Name': 'Race', 'OID': 'IT.RACE_BOOLEAN'}
{'DataType': 'text', 'Length': '20', 'Name': 'Other Race', 'OID': 'IT.RACEOTH'}
</code></pre>
<p>Notice that the output is a series of dictionaries with keys indicating aspects like 'Name' and 'OID' (a unique ID for each object in the XML). We can extract these to convert the coded column names into names that show what each column actually represents. To do this, we'll create a dictionary with each column's OID as the key and the column name as the value, as shown below:</p>
<pre><code class="lang-python">names = {}
<span class="hljs-keyword">for</span> meta <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//ItemDef'</span>, ns):
    names[meta.attrib[<span class="hljs-string">'OID'</span>]] = meta.attrib[<span class="hljs-string">'Name'</span>]
names
</code></pre>
<pre><code class="lang-txt">{'IT.DOB': 'Date of birth',
'IT.SEX': 'Sex',
'IT.ETHNIC': 'Ethnicity',
'IT.RACE_CODE': 'Race code',
'IT.RACE_BOOLEAN': 'Race',
'IT.RACEOTH': 'Other Race'}
</code></pre>
<p>Now, with the <code>rename</code> function from pandas, we can change the column names in <code>results</code>, and things start to make more sense.</p>
<pre><code class="lang-python">results = results.rename(columns=names)
results
</code></pre>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Variable</td><td>ID</td><td>Date of birth</td><td>Ethnicity</td><td>Sex</td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td>001</td><td>1957-05-07</td><td>2</td><td>1</td></tr>
<tr>
<td>1</td><td>002</td><td>1975-01-31&gt;</td><td>2</td><td>2</td></tr>
<tr>
<td>2</td><td>003</td><td>1961-06-09</td><td>1</td><td>2</td></tr>
</tbody>
</table>
</div><p>We also have two columns here that are in numeric codes: <code>Ethnicity</code> and <code>Sex</code>. The definitions of these codes are usually at the beginning of the XML document, along with the metadata. To get the names of the sex and ethnicity codes, in this case, there is a tag that will be our target: <code>CodeList</code>. The code below shows how the tag is structured:</p>
<pre><code class="lang-python">print(etree.tostring(tree.find(<span class="hljs-string">'.//CodeList'</span>, ns), pretty_print = <span class="hljs-literal">True</span>, encoding = str))
</code></pre>
<pre><code class="lang-txt">    &lt;CodeList xmlns="http://www.cdisc.org/ns/odm/v2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlink="http://www.w3.org/1999/xlink" DataType="integer" Name="Sex" OID="CL.SEX"&gt;
                &lt;CodeListItem CodedValue="1"&gt;
                   &lt;Decode&gt;
                      &lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Male&lt;/TranslatedText&gt;
                   &lt;/Decode&gt;
                &lt;/CodeListItem&gt;
                &lt;CodeListItem CodedValue="2"&gt;
                   &lt;Decode&gt;
                      &lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Female&lt;/TranslatedText&gt;
                   &lt;/Decode&gt;
                &lt;/CodeListItem&gt;
             &lt;/CodeList&gt;
</code></pre>
<p>Now, recall the previous method we used to get column names. Basically, the principle for obtaining the values of numeric codes is the same; however, it is a bit more complex, requiring a few more lines of code. When accessing the <code>CodeList</code> tag, if we want to extract values for <code>Ethnicity</code>, we need to filter by mentioning the name of this attribute using XPATH. This comes right after the tag name; thus, we can create a new dictionary, <code>ethnicity</code>, to hold codes and values for the ethnicities represented in the DataFrame.</p>
<pre><code class="lang-python">ethnicity = {}
<span class="hljs-keyword">for</span> eth <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//CodeList[@Name="Ethnicity"]'</span>, ns):
    <span class="hljs-keyword">for</span> code <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//CodeList[@Name="Ethnicity"]/CodeListItem'</span>, ns):
        <span class="hljs-keyword">for</span> decode <span class="hljs-keyword">in</span> code:
            <span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> decode:
                ethnicity[code.attrib[<span class="hljs-string">'CodedValue'</span>]] = name.text
ethnicity
</code></pre>
<pre><code class="lang-txt">{'1': 'Hispanic', '2': 'Non-hispanic'}
</code></pre>
<p>To get the values of the codes in the <code>Sex</code> column, just use the same method as before, only replacing the name of the attribute to be filtered.</p>
<pre><code class="lang-python">sex = {}
<span class="hljs-keyword">for</span> eth <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//CodeList[@Name="Sex"]'</span>, ns):
    <span class="hljs-keyword">for</span> code <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//CodeList[@Name="Sex"]/CodeListItem'</span>, ns):
        <span class="hljs-keyword">for</span> decode <span class="hljs-keyword">in</span> code:
            <span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> decode:
                sex[code.attrib[<span class="hljs-string">'CodedValue'</span>]] = name.text
sex
</code></pre>
<pre><code class="lang-txt">{'1': 'Male', '2': 'Female'}
</code></pre>
<p>With the dictionaries ready, we can proceed with the remaining substitutions. Here, we'll use the pandas <code>map</code> function, which associates the keys (i.e., the numeric codes) of the dictionaries we created with the values that name the numbers. We'll do this for both columns, <code>Ethnicity</code> and <code>Sex</code>; notice that the spreadsheet now makes much more sense and is ready for the desired analyses.</p>
<pre><code class="lang-python">results[<span class="hljs-string">'Ethnicity'</span>] = results[<span class="hljs-string">'Ethnicity'</span>].map(ethnicity)
results[<span class="hljs-string">'Sex'</span>] = results[<span class="hljs-string">'Sex'</span>].map(sex)
results
</code></pre>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Variable</td><td>ID</td><td>Date of birth</td><td>Ethnicity</td><td>Sex</td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td>001</td><td>1957-05-07</td><td>Non-hispanic</td><td>Male</td></tr>
<tr>
<td>1</td><td>002</td><td>1975-01-31&gt;</td><td>Non-hispanic</td><td>Female</td></tr>
<tr>
<td>2</td><td>003</td><td>1961-06-09</td><td>Hispanic</td><td>Female</td></tr>
</tbody>
</table>
</div><p>To save the DataFrame that was created, simply use the built-in <code>pandas</code> functions for this purpose. This way, the extracted information will be stored in a file that is lighter and faster to handle.</p>
<pre><code class="lang-python"><span class="hljs-comment">## Exportando</span>

results.to_csv(<span class="hljs-string">'results.csv'</span>) <span class="hljs-comment">#.csv file</span>
results.to_excel(<span class="hljs-string">'results.xlsx'</span>) <span class="hljs-comment">#.xlsx file</span>
results.to_parquet(<span class="hljs-string">'results.parquet'</span>) <span class="hljs-comment">#.parquet file</span>
</code></pre>
<h2 id="heading-notes">Notes</h2>
<hr />
<p>1. This is succinctly and very well supported in Shabo et al. (2006): “The Clinical Data Interchange Standards Consortium (CDISC) is leading the development of standards to improve data quality and accelerate product development in the pharmaceutical industry.19 The CDISC model focuses on the use of metadata, and the approach is to combine XML representation with the tabular presentation traditionally used for clinical-trial data.” - Shabo, A., S. Rabinovici-Cohen, e P. Vortman. “Revolutionary impact of XML on biomedical information interoperability”. IBM Systems Journal 45, nº 2 (2006): 361–72. <a target="_blank" href="https://doi.org/10.1147/sj.452.0361">https://doi.org/10.1147/sj.452.0361</a>. <a class="post-section-overview" href="#um">↩</a></p>
<p>2. “Interest in ODM as a research topic has grown significantly over the last several years with increasing interest in the CDISC data standards from regulatory authorities such as the FDA and the Japanese Pharmaceutical and Medical Devices Agency (PMDA)” - Hume, Sam, Jozef Aerts, Surendra Sarnikar, e Vojtech Huser. “Current Applications and Future Directions for the CDISC Operational Data Model Standard: A Methodological Review”. Journal of Biomedical Informatics 60 (abril de 2016): 352–62. <a target="_blank" href="https://doi.org/10.1016/j.jbi.2016.02.016">https://doi.org/10.1016/j.jbi.2016.02.016</a>. <a class="post-section-overview" href="#dois">↩</a></p>
<p>3. “While it is a requirement to submit pre-clinical and clinical data in CDISC format to regulatory bodies such as the US FDA and Japan’s Pharmaceuticals and Medical Devices Agency (PDMA), the actual usage of CDISC standards spans a much wider array of entities.” Hufstedler, Heather, Yannik Roell, Andressa Peña, Ankur Krishnan, Ian Green, Adriano Barbosa-Silva, Andreas Kremer, et al. “Navigating data standards in public health: A brief report from a data-standards meeting”. Journal of Global Health 14 ([s.d.]): 03024. <a target="_blank" href="https://doi.org/10.7189/jogh.14.03024">https://doi.org/10.7189/jogh.14.03024</a>. <a class="post-section-overview" href="#tres">↩</a></p>
<p>4. "The CDISC Operational Data Model (ODM) is an XML format that facilitates the exchange of clinical data captured during a clinical study. ODMbased files contain the study data and the associated descriptions of the data items, their groupings into Case Report Forms (CRFs), which are electronic documents to record the study data, and the associated questions and code lists. Furthermore, the FDA has mandated the use of other CDISC standards in clinical studies." Leroux, Hugo, e Laurent Lefort. “Semantic Enrichment of Longitudinal Clinical Study Data Using the CDISC Standards and the Semantic Statistics Vocabularies”. Journal of Biomedical Semantics 6, nº 1 (dezembro de 2015): 16. <a target="_blank" href="https://doi.org/10.1186/s13326-015-0012-6">https://doi.org/10.1186/s13326-015-0012-6</a>. <a class="post-section-overview" href="#quatro">↩</a></p>
<p>5. “The Federal Drug Administration has mandated the use of the CDISC standards for the electronic capture and reporting of clinical study data” Leroux, Hugo, Alejandro Metke-Jimenez, e Michael J. Lawley. “Towards Achieving Semantic Interoperability of Clinical Study Data with FHIR”. Journal of Biomedical Semantics 8, nº 1 (19 de setembro de 2017): 41. <a target="_blank" href="https://doi.org/10.1186/s13326-017-0148-7">https://doi.org/10.1186/s13326-017-0148-7</a>. <a class="post-section-overview" href="#cinco">↩</a></p>
<p>6. Lefort, Laurent, e Hugo Leroux. “Design and generation of Linked Clinical Data Cubes”, 2013. <a target="_blank" href="https://doi.org/10.13140/RG.2.1.3677.2967">https://doi.org/10.13140/RG.2.1.3677.2967</a>. <a class="post-section-overview" href="#seis">↩</a></p>
<p>7. Brix, Tobias Johannes, Philipp Bruland, Saad Sarfraz, Jan Ernsting, Philipp Neuhaus, Michael Storck, Justin Doods, Sonja Ständer, e Martin Dugas. “ODM Data Analysis—A Tool for the Automatic Validation, Monitoring and Generation of Generic Descriptive Statistics of Patient Data”. PLOS ONE 13, nº 6 (22 de junho de 2018): e0199242. <a target="_blank" href="https://doi.org/10.1371/journal.pone.0199242">https://doi.org/10.1371/journal.pone.0199242</a>. <a class="post-section-overview" href="#sete">↩</a></p>
<p>8. <strong>An important note</strong>: From now on, in addition to Python libraries and XML, we will use another language, this one for querying: <em>XPath</em>. With it, we can properly access XML elements and attributes. I won't go into details about it in this article, but if you want to understand more about it, you can see more details <a target="_blank" href="https://escoladedados.org/tutoriais/xpath-para-raspagem-de-dados-em-html/">here</a> and <a target="_blank" href="https://www.w3schools.com/xml/xpath_intro.asp">here</a>, as well as a good cheat sheet <a target="_blank" href="https://devhints.io/xpath">here</a>. We won't use many different things from this language here, but it's interesting to explore it further later.. <a class="post-section-overview" href="#oito">↩</a></p>
<hr />
]]></content:encoded></item><item><title><![CDATA[XML na Prática: Como lidar com documento ODM-XML usando Python]]></title><description><![CDATA[Contexto
Em estudos clínicos, é comum trabalharmos com conjuntos de dados que podem vir em variados formatos, dependendo do que o sistema EDC escolhido consegue oferecer. Entretanto, em algumas situações, será preciso extrair um conjunto de dados com...]]></description><link>https://blog.matheusyuri.pro/xml-na-pratica</link><guid isPermaLink="true">https://blog.matheusyuri.pro/xml-na-pratica</guid><category><![CDATA[xml]]></category><category><![CDATA[xml-parsing]]></category><category><![CDATA[clinical trials]]></category><category><![CDATA[EDC systems]]></category><category><![CDATA[OpenClinica]]></category><category><![CDATA[REDCap]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Sun, 04 Aug 2024 03:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1723039980129/26b38fb7-a79e-4e32-9150-00aaa51f07cf.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-contexto">Contexto</h2>
<p>Em estudos clínicos, é comum trabalharmos com conjuntos de dados que podem vir em variados formatos, dependendo do que o sistema <a target="_blank" href="https://en.wikipedia.org/wiki/Electronic_data_capture">EDC</a> escolhido consegue oferecer. Entretanto, em algumas situações, será preciso extrair um conjunto de dados completo, de acordo com o que as entidades regulatórias exigem nas submissões de aprovação do uso de medicamentos e vacinas, principalmente. A partir disso, não há muita escolha; sempre aparecerá como a opção mais facilitada um documento XML. Para quem está acostumado a lidar com todo tipo de dado, talvez um pouco de esforço terá de ser feito pra transformar isso em algo que possa ser usados em várias análises. E para quem está acostmado a lidar apenas com dados estruturados (planilhas), o desespero bate. E agora? O que fazer?</p>
<p>Neste artigo, veremos um pouco dos segredos que escondem um documento ODM-XML, além de como podemos extrair esses segredos, e produzir uma planilha com algo que faça sentido na hora das análises de dados de estudos clínicos.</p>
<h2 id="heading-por-que-xml">Por que XML?</h2>
<p>Num apanhado geral, <a target="_blank" href="https://aws.amazon.com/what-is/xml/">há alguns (bons) motivos para se usar XML ao lidar com dados</a>. Exemplificando:</p>
<ul>
<li><p><strong>É possível criar um arquivo que pode ser utilizado com as mais variadas ferramentas de manipulação de dados</strong>. Sendo o documento XML um arquivo de texto, pode ser transferido de uma tecnologia para outra sem maior esforço; muitas tecnologias, por isso mesmo, conseguem ler e processar XML (alguns exemplos podem ser vistos <a target="_blank" href="https://www.researchgate.net/publication/309022617_Comparing_Common_Programming_Languages_to_Parse_Big_XML_File_in_Terms_of_Executing_Time_Memory_Usage_CPU_Consumption_and_Line_Number_on_Two_Platforms">aqui</a>.</p>
</li>
<li><p><strong>Mantém a integridade dos dados</strong>, o que é um aspecto vital na hora de lidar com base de dados. Isso é feito a partir da concentração de aspectos como metadados e dados dentro de um só arquivo, fazendo com que todos os recursos estejam à disposição sem precisar importar outros arquivos (e isto iremos explorar de forma um pouco mais detalhada ao longo do artigo)<a class="post-section-overview" href="#um"><sup>1</sup></a>.</p>
</li>
<li><p><strong>A organização e categorização dos dados é mais eficiente</strong>, fazendo com que a busca por uma determinada informação dentro de um documento XML seja mais rápida e menos, digamos, "dolorosa".</p>
</li>
</ul>
<h2 id="heading-o-que-e-odm">O que é ODM?</h2>
<p><a target="_blank" href="https://www.altexsoft.com/blog/cdisc-standards/">ODM</a> é a sigla para <em>Operational Data Model</em>. Segundo o <a target="_blank" href="https://www.cdisc.org/standards/data-exchange/odm">CDISC</a>, "é um formato que pode ser utilizado para armazenar, intercambiar entre sistemas de gestão de dados, bem como para armazenar os dados, metadados, e dados administrativos referentes a um estudo clínico". Para algumas entidades regulatórias de saúde, como a FDA dos Estados Unidos <a class="post-section-overview" href="#dois"><sup>2</sup></a><a class="post-section-overview" href="#tres"><sup>3</sup></a><a class="post-section-overview" href="#quatro"><sup>4</sup></a><a class="post-section-overview" href="#cinco"><sup>5</sup></a>, o CDISC sugeriu este formato como o padrão para arquivamento de dados, por sua capacidade de carregar todas as informações pertinentes a estudos clínicos em um só arquivo intercambiável, quando preciso.</p>
<p>O modelo ODM oferece um modelo XML que facilita a captura de dados clínicos; a partir de um esquema como o da figura abaixo, podemos dividir o documento XML em duas partes principais: a de metadados, que dá a definição das variáveis que serão utilizadas, e a dos dados propriamente ditos, onde estarão depositados as informações do estudo clínico.</p>
<p><img src="https://www.researchgate.net/profile/Hugo-Leroux/publication/259220016/figure/fig1/AS:297314913669122@1447896807509/Structure-of-CDISC-ODM-XML-schema-adapted-from-ODM-11-documentation-9.png" alt="None" />
O esquema de um documento XML para dados clínicos, segundo o modelo ODM estabelecido pelo CDISC. <a class="post-section-overview" href="#seis"><sup>6</sup></a></p>
<p><img src="https://i.ibb.co/PCBCnZG/pone-0199242-g001.png" alt="None" />
Outro esquema de um documento XML para dados clínicos. <a class="post-section-overview" href="#sete"><sup>7</sup></a></p>
<h2 id="heading-importando-bibliotecas">Importando bibliotecas</h2>
<p>Ao usar o Python para extrair dados de documentos <code>.xml</code>, é preciso importar algumas bibliotecas; se você usa plataformas como o <a target="_blank" href="https://www.anaconda.com/">Anaconda</a> ou o <a target="_blank" href="https://winpython.github.io/">WinPython</a>, é provável que apenas o uso do <code>import</code> já seja o suficiente. Se você estiver usando uma versão "pura" do Python, recomendo que, antes de executar os passos a seguir, seja feita a instalação das bibliotecas usando o <a target="_blank" href="https://pt.wikipedia.org/wiki/Pip_(gerenciador_de_pacotes)"><code>pip</code></a>.</p>
<p>Neste artigo, usaremos bibliotecas como:</p>
<ul>
<li><p><a target="_blank" href="https://requests.readthedocs.io/en/latest/"><code>requests</code></a>, a biblioteca mais simples para requisições envolvendo páginas web (porque de complexa já basta a vida);</p>
</li>
<li><p><a target="_blank" href="https://lxml.de/"><code>lxml</code></a>, outra biblioteca 'easy-to-use', esta para processar os arquivos XML;</p>
</li>
<li><p><a target="_blank" href="https://pandas.pydata.org/"><code>pandas</code></a>, que é a biblioteca mais conhecida para manipulação e análise de dados; com ela, será possível construir uma planilha com os dados do XML.</p>
</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> lxml <span class="hljs-keyword">import</span> etree <span class="hljs-comment">#Neste caso, usaremos a API da biblioteca 'ElementTree' que está disponível na biblioteca 'lxml'</span>
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
</code></pre>
<h2 id="heading-obtendo-os-dados">Obtendo os dados</h2>
<p>O documento <code>.xml</code> que será utilizado origina-se de um <a target="_blank" href="https://github.com/cdisc-org/DataExchange-ODM">repositório no GitHub da CDISC</a>; para obtê-lo diretamente, i.e., sem precisar fazer o download de qualquer arquivo, usaremos a biblioteca <code>requests</code>. A função <a target="_blank" href="https://www.w3schools.com/python/ref_requests_get.asp"><code>get</code></a> dessa biblioteca faz uma requisição a uma página do GitHub que contém o arquivo, e espera uma resposta dessa página em forma de código, que estamos armazenando na variável <code>response</code>. Se a resposta for o código <code>200</code>, <a target="_blank" href="https://www.geeksforgeeks.org/response-methods-python-requests/">significa que a requisição foi bem-sucedida</a>.</p>
<pre><code class="lang-python">url = <span class="hljs-string">'https://github.com/cdisc-org/DataExchange-ODM/raw/main/examples/Demographics_RACE/Demographics_RACE_check_all_that_apply.xml'</span>
response = requests.get(url)
print(response)
</code></pre>
<pre><code class="lang-txt">&lt;Response [200]&gt;
</code></pre>
<p>A partir dessa resposta, utilizaremos o objeto <a target="_blank" href="https://www.geeksforgeeks.org/response-content-python-requests/"><code>content</code></a> para de fato obter o XML que será explorado. O conteúdo estará disponível na variável <code>tree</code>, conforme o código que está abaixo:</p>
<pre><code class="lang-python">tree = response.content
</code></pre>
<p>A variável <code>tree</code> nos acompanhará durante todo o processo de construção da planilha a partir das informações que temos.</p>
<h2 id="heading-fazendo-a-transformacao-e-verificando-a-estrutura-do-xml">Fazendo a transformação e verificando a estrutura do XML</h2>
<p>Feita a extração do conteúdo que está na página do GitHub, é possível observar a estrutura do XML que será explorado, quando o conteúdo será transformado em uma variável legível; isso é importante para serem localizadas as tags, atributos, e valores onde estão os dados que interessam de fato.</p>
<p>A partir daqui, começamos o uso de outra biblioteca que importamos: <code>lxml</code>, que se dedicará à obtenção dos elementos XML que já foram mencionados. Armazenaremos o XML inteiro na variável <code>tree</code>, onde serão passados o conteúdo da página do GitHub, além do tipo de parser (o transformador) que será utilizado. A variável <code>tree2</code>, neste caso, serve para podermos observar de fato o "esqueleto" do XML.</p>
<pre><code class="lang-python">tree = etree.XML(tree, etree.XMLParser(remove_comments=<span class="hljs-literal">True</span>))
tree2 = etree.tostring(tree, pretty_print = <span class="hljs-literal">True</span>, encoding = str)
print(tree2)
</code></pre>
<pre><code class="lang-txt">    &lt;ODM xmlns="http://www.cdisc.org/ns/odm/v2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlink="http://www.w3.org/1999/xlink" CreationDateTime="2020-07-06T10:20:15+01:00" FileOID="DEMOGRAPHICS_EXAMPLE" FileType="Snapshot" Granularity="Metadata" ODMVersion="2.0" SourceSystem="XML4Pharma CDISC ODM Study Designer" SourceSystemVersion="2015-R1"&gt;
       &lt;Study OID="ST.DEMOGRAPHICS_EXAMPLE" StudyName="Study with Demographics example" ProtocolName="MyStudy"&gt;
          &lt;Description&gt;&lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Demographics example with Race, with "check all that apply"&lt;/TranslatedText&gt;&lt;/Description&gt;
          &lt;MetaDataVersion Name="Version 1" OID="MV.1.0"&gt;
             &lt;Description&gt;&lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Version 1&lt;/TranslatedText&gt;&lt;/Description&gt;
             &lt;StudyEventDef Name="Screening visit with demographics" OID="SE.SCREENING" Repeating="No" Type="Scheduled"&gt;
                &lt;ItemGroupRef ItemGroupOID="FO.DEMOGRAPHICS" Mandatory="Yes"/&gt;
             &lt;/StudyEventDef&gt;
             &lt;ItemGroupDef Name="Demographics form" OID="FO.DEMOGRAPHICS" Type="Form" Repeating="No"&gt;
                &lt;ItemGroupRef ItemGroupOID="IG.DEMOGRAPHICS" Mandatory="Yes"/&gt;
             &lt;/ItemGroupDef&gt;
             &lt;ItemGroupDef Name="Demographics" OID="IG.DEMOGRAPHICS" Type="Section" Repeating="No"&gt;
                &lt;ItemRef ItemOID="IT.DOB" Mandatory="Yes"/&gt;
                &lt;ItemRef ItemOID="IT.SEX" Mandatory="Yes"/&gt;
                &lt;ItemRef ItemOID="IT.ETHNIC" Mandatory="Yes"/&gt;


                &lt;ItemGroupRef ItemGroupOID="IG.RACE" Mandatory="Yes"/&gt;
             &lt;/ItemGroupDef&gt;

             ...

             &lt;CodeList DataType="integer" Name="Sex" OID="CL.SEX"&gt;
                &lt;CodeListItem CodedValue="1"&gt;
                   &lt;Decode&gt;
                      &lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Male&lt;/TranslatedText&gt;
                   &lt;/Decode&gt;
                &lt;/CodeListItem&gt;
                &lt;CodeListItem CodedValue="2"&gt;
                   &lt;Decode&gt;
                      &lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Female&lt;/TranslatedText&gt;
                   &lt;/Decode&gt;
                &lt;/CodeListItem&gt;
             &lt;/CodeList&gt;
             &lt;CodeList DataType="integer" Name="Ethnicity" OID="CL.ETHNIC"&gt;
                &lt;CodeListItem CodedValue="1"&gt;
                   &lt;Decode&gt;
                      &lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Hispanic&lt;/TranslatedText&gt;
                   &lt;/Decode&gt;
                &lt;/CodeListItem&gt;
                &lt;CodeListItem CodedValue="2"&gt;
                   &lt;Decode&gt;
                      &lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Non-hispanic&lt;/TranslatedText&gt;
                   &lt;/Decode&gt;
                &lt;/CodeListItem&gt;
             &lt;/CodeList&gt;

             ...

          &lt;/MetaDataVersion&gt;
       &lt;/Study&gt;

       &lt;ClinicalData StudyOID="ST.DEMOGRAPHICS_EXAMPLE" MetaDataVersionOID="MV.1.0"&gt;

          &lt;SubjectData SubjectKey="001"&gt;
             &lt;StudyEventData StudyEventOID="SE.SCREENING"&gt;
                &lt;ItemGroupData ItemGroupOID="FO.DEMOGRAPHICS"&gt;
                   &lt;ItemGroupData ItemGroupOID="IG.DEMOGRAPHICS"&gt;
                      &lt;ItemData ItemOID="IT.DOB"&gt;&lt;Value&gt;1957-05-07&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.SEX"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.ETHNIC"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;

                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="1"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;

                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="2"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;true&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="3"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;3&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="4"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;4&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;4&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="5"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;5&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="6"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;99&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                   &lt;/ItemGroupData&gt;
                &lt;/ItemGroupData&gt;
             &lt;/StudyEventData&gt;
          &lt;/SubjectData&gt;

          ...

          &lt;SubjectData SubjectKey="003"&gt;
             &lt;StudyEventData StudyEventOID="SE.SCREENING"&gt;
                &lt;ItemGroupData ItemGroupOID="FO.DEMOGRAPHICS"&gt;
                   &lt;ItemGroupData ItemGroupOID="IG.DEMOGRAPHICS"&gt;
                      &lt;ItemData ItemOID="IT.DOB"&gt;&lt;Value&gt;1961-06-09&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.SEX"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.ETHNIC"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;

                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="1"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="2"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="3"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;3&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="4"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;4&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="5"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;5&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="6"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;99&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;true&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACEOTH"&gt;&lt;Value&gt;Native Amazonian&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                   &lt;/ItemGroupData&gt;
                &lt;/ItemGroupData&gt;
             &lt;/StudyEventData&gt;
          &lt;/SubjectData&gt;
       &lt;/ClinicalData&gt;
    &lt;/ODM&gt;
</code></pre>
<h2 id="heading-verificando-os-namespaces">Verificando os namespaces</h2>
<p>Ao explorarmos um XML, é essencial que tomemos conhecimento dos <a target="_blank" href="https://en.wikipedia.org/wiki/XML_namespace">namespaces</a> que este possui. Os namespaces podem servir de identificação única para cada tag componente. O uso de namespaces é recomendado pela W3C, e se vê muito necessário quando temos tags ou atributos de nome semelhante, mas associado a elementos ou tags diferentes. Para vermos quais namespaces aparecem no documento XML, utliza-se o objeto <a target="_blank" href="https://lxml.de/4.3/api/lxml.etree._Element-class.html"><code>nsmap</code></a>, como abaixo:</p>
<pre><code class="lang-python">ns = tree.nsmap
print(ns)
</code></pre>
<pre><code class="lang-txt">{None: 'http://www.cdisc.org/ns/odm/v2.0', 'xs': 'http://www.w3.org/2001/XMLSchema', 'xlink': 'http://www.w3.org/1999/xlink'}
</code></pre>
<h2 id="heading-verificando-as-tags">Verificando as tags</h2>
<p>Tendo já conhecimento dos namespaces, podemos agora analisar quais são os nomes daquilo que chamamos de <em>tags</em>. É através desses nomes que será possível extrair os dados de interesse mais para frente.</p>
<pre><code class="lang-python">elements = []
<span class="hljs-keyword">for</span> elem <span class="hljs-keyword">in</span> tree.iter():
    elements.append(elem.tag)

elements = list(set(elements))
print(elements)
</code></pre>
<pre><code class="lang-txt">['{http://www.cdisc.org/ns/odm/v2.0}TranslatedText', '{http://www.cdisc.org/ns/odm/v2.0}Description', '{http://www.cdisc.org/ns/odm/v2.0}ItemGroupDef', '{http://www.cdisc.org/ns/odm/v2.0}Decode', '{http://www.cdisc.org/ns/odm/v2.0}ClinicalData', '{http://www.cdisc.org/ns/odm/v2.0}ODM', '{http://www.cdisc.org/ns/odm/v2.0}ItemGroupData', '{http://www.cdisc.org/ns/odm/v2.0}ItemRef', '{http://www.cdisc.org/ns/odm/v2.0}Question', '{http://www.cdisc.org/ns/odm/v2.0}CodeListItem', '{http://www.cdisc.org/ns/odm/v2.0}SubjectData', '{http://www.cdisc.org/ns/odm/v2.0}ItemGroupRef', '{http://www.cdisc.org/ns/odm/v2.0}MetaDataVersion', '{http://www.cdisc.org/ns/odm/v2.0}StudyEventData', '{http://www.cdisc.org/ns/odm/v2.0}Study', '{http://www.cdisc.org/ns/odm/v2.0}Value', '{http://www.cdisc.org/ns/odm/v2.0}CodeListRef', '{http://www.cdisc.org/ns/odm/v2.0}StudyEventDef', '{http://www.cdisc.org/ns/odm/v2.0}ItemDef', '{http://www.cdisc.org/ns/odm/v2.0}ItemData', '{http://www.cdisc.org/ns/odm/v2.0}CodeList']
</code></pre>
<h2 id="heading-extraindo-os-primeiros-atributos">Extraindo os primeiros atributos</h2>
<p>Sabendo já como o arquivo XML está estruturado, bem como quais são as tags que estão presentes, é possível selecionar os locais onde estão os dados de interesse. A próxima coisa a se fazer é analisar o que está dentro das tags. A esse conteúdo damos o nome de atributos. Atributos são partes internas das tags que obedecem um padrão <code>'Nome="Valor"'</code>. Perceba o atributo <code>'ItemOID'</code> no final da primeira linha; ele vem acompanhado de um valor <code>"IT.DOB"</code>. Este é o padrão utilizado e recomendado pela W3C quando se tratam de atributos. <a class="post-section-overview" href="#oito"><sup>8</sup></a></p>
<pre><code class="lang-python">print(etree.tostring(tree.find(<span class="hljs-string">'.//ItemData'</span>, ns), pretty_print = <span class="hljs-literal">True</span>, encoding = str))
</code></pre>
<pre><code class="lang-txt">    &lt;ItemData xmlns="http://www.cdisc.org/ns/odm/v2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlink="http://www.w3.org/1999/xlink" ItemOID="IT.DOB"&gt;
      &lt;Value&gt;1957-05-07&lt;/Value&gt;
    &lt;/ItemData&gt;
</code></pre>
<p>Para acessar os atributos de uma tag em específico, é possível utilizar duas funções do <code>lxml</code>, dependendo da situação: <a target="_blank" href="https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.find"><code>find</code></a> e <a target="_blank" href="https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.findall"><code>findall</code></a>. A primeira serve para resgatar somente a primeira ocorrência de uma tag no arquivo XML, enquanto que a outra retorna todas as ocorrências de tags com o nome mencionado.</p>
<pre><code class="lang-python">tree.find(<span class="hljs-string">'.//ClinicalData'</span>, ns) <span class="hljs-comment">#Apenas a primeira ocorrência da tag ClinicalData</span>
</code></pre>
<pre><code class="lang-txt">&lt;Element {http://www.cdisc.org/ns/odm/v2.0}ClinicalData at 0x21052103e80&gt;
</code></pre>
<pre><code class="lang-python">tree.findall(<span class="hljs-string">'.//SubjectData'</span>, ns) <span class="hljs-comment">#Todas as ocorrências da tag SubjectData</span>
</code></pre>
<pre><code class="lang-txt">[&lt;Element {http://www.cdisc.org/ns/odm/v2.0}SubjectData at 0x21052102e00&gt;,
&lt;Element {http://www.cdisc.org/ns/odm/v2.0}SubjectData at 0x21052108540&gt;,
&lt;Element {http://www.cdisc.org/ns/odm/v2.0}SubjectData at 0x21052108840&gt;]
</code></pre>
<p>Perceba que, ao usarmos estas funções, o retorno é um objeto de classe <a target="_blank" href="https://docs.python.org/3/library/xml.etree.elementtree.html#element-objects"><code>Element</code></a>; contudo, não é exatamente isso que está sendo procurado. Para buscar o que realmente são as tags e os atributos dentro delas, podemos nos valer de dois objetos, cujos nomes são sugestivos: <code>attrib</code> e <code>tag</code>. No caso do atributo, os resultados retornam em forma de dicionário, onde a chave é o nome do atributo, e o valor é o valor desse mesmo atributo. A função <code>tag</code>, por sua vez, retorna os nomes das tags que foram mencionadas.</p>
<pre><code class="lang-python">tree.find(<span class="hljs-string">'.//ClinicalData'</span>, ns).attrib <span class="hljs-comment">#Atributos apenas da primeira (e única) tag ClinicalData</span>
</code></pre>
<pre><code class="lang-txt">{'StudyOID': 'ST.DEMOGRAPHICS_EXAMPLE', 'MetaDataVersionOID': 'MV.1.0'}
</code></pre>
<pre><code class="lang-python"><span class="hljs-keyword">for</span> subject <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//SubjectData'</span>, ns):
    subj = subject.attrib <span class="hljs-comment">#Atributos de cada tag SubjectData</span>
    print(subj)
</code></pre>
<pre><code class="lang-txt">{'SubjectKey': '001'}
{'SubjectKey': '002'}
{'SubjectKey': '003'}
</code></pre>
<pre><code class="lang-python">tree.find(<span class="hljs-string">'.//SubjectData'</span>, ns).tag <span class="hljs-comment">#Nome da tag SubjectData</span>
</code></pre>
<pre><code class="lang-txt">'{http://www.cdisc.org/ns/odm/v2.0}SubjectData'
</code></pre>
<pre><code class="lang-python"><span class="hljs-keyword">for</span> subject <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//SubjectData'</span>, ns):
    <span class="hljs-keyword">for</span> eve <span class="hljs-keyword">in</span> subject:
        print(eve.attrib) <span class="hljs-comment">#Atributos das tags StudyEventData</span>
</code></pre>
<pre><code class="lang-txt">{'StudyEventOID': 'SE.SCREENING'}
{'StudyEventOID': 'SE.SCREENING'}
{'StudyEventOID': 'SE.SCREENING'}
</code></pre>
<pre><code class="lang-python"><span class="hljs-keyword">for</span> subject <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//SubjectData'</span>, ns):
    <span class="hljs-keyword">for</span> event <span class="hljs-keyword">in</span> subject:
        <span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> event:
            ite = item.attrib
            print(ite) <span class="hljs-comment">#Atributos da tag ItemGroupDef</span>
</code></pre>
<pre><code class="lang-txt">{'ItemGroupOID': 'FO.DEMOGRAPHICS'}
{'ItemGroupOID': 'FO.DEMOGRAPHICS'}
{'ItemGroupOID': 'FO.DEMOGRAPHICS'}
</code></pre>
<p>Caso se queira extrair somente o valor de um determinado atributo, basta fazer uma seleção do atributo com seu nome em colchetes, o mesmo que se faz quando se quer descobrir o valor de uma determinada chave armazenada em um dicionário:</p>
<pre><code class="lang-python">print(subj[<span class="hljs-string">'SubjectKey'</span>]) <span class="hljs-comment">#Valor do atributo SubjectKey na última tag SubjectData</span>
</code></pre>
<pre><code class="lang-txt">003
</code></pre>
<h2 id="heading-verificando-a-estrutura-do-xml-para-apenas-um-individuo">Verificando a estrutura do XML para apenas um indivíduo</h2>
<p>Nós já vimos como fazer uma filtragem de uma ou mais tags através de seus nomes, e descobrir os atributos e seus valores. Caso seja interessante ou necessário analisar mais a fundo a estrutura XML de apenas uma ocorrência de tag (nesse caso, um indivíduo), basta utilizar a função <code>find</code>, que já conhecemos. Com o código abaixo, podemos verificar a estrutura do XML para o primeiro indivíduo.</p>
<pre><code class="lang-python">print(etree.tostring(tree.find(<span class="hljs-string">'.//SubjectData'</span>, ns), pretty_print = <span class="hljs-literal">True</span>, encoding = str))
</code></pre>
<pre><code class="lang-txt">    &lt;SubjectData xmlns="http://www.cdisc.org/ns/odm/v2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlink="http://www.w3.org/1999/xlink" SubjectKey="001"&gt;
             &lt;StudyEventData StudyEventOID="SE.SCREENING"&gt;
                &lt;ItemGroupData ItemGroupOID="FO.DEMOGRAPHICS"&gt;
                   &lt;ItemGroupData ItemGroupOID="IG.DEMOGRAPHICS"&gt;
                      &lt;ItemData ItemOID="IT.DOB"&gt;&lt;Value&gt;1957-05-07&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.SEX"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.ETHNIC"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;

                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="1"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;

                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="2"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;true&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="3"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;3&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="4"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;4&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;4&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="5"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;5&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="6"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;99&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                   &lt;/ItemGroupData&gt;
                &lt;/ItemGroupData&gt;
             &lt;/StudyEventData&gt;
          &lt;/SubjectData&gt;
</code></pre>
<p>Agora, se queremos filtrar as tags e atributos referentes a um outro indivíduo em específico, é preciso mencionar o atributo <code>SubjectKey</code> e mencionar o valor do indivíduo (no caso, '002'), como o código abaixo:</p>
<pre><code class="lang-python">print(etree.tostring(tree.find(<span class="hljs-string">'.//SubjectData[@SubjectKey="002"]'</span>, ns), pretty_print = <span class="hljs-literal">True</span>, encoding = str))
</code></pre>
<pre><code class="lang-txt">    &lt;SubjectData xmlns="http://www.cdisc.org/ns/odm/v2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlink="http://www.w3.org/1999/xlink" SubjectKey="002"&gt;
             &lt;StudyEventData StudyEventOID="SE.SCREENING"&gt;
                &lt;ItemGroupData ItemGroupOID="FO.DEMOGRAPHICS"&gt;
                   &lt;ItemGroupData ItemGroupOID="IG.DEMOGRAPHICS"&gt;
                      &lt;ItemData ItemOID="IT.DOB"&gt;&lt;Value&gt;1975-01-31&amp;gt;&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.SEX"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;ItemData ItemOID="IT.ETHNIC"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;

                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="1"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;1&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="2"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;2&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="3"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;3&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;true&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="4"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;4&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="5"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;5&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                      &lt;ItemGroupData ItemGroupOID="IG.RACE" ItemGroupRepeatKey="6"&gt;
                         &lt;ItemData ItemOID="IT.RACE_CODE"&gt;&lt;Value&gt;99&lt;/Value&gt;&lt;/ItemData&gt;
                         &lt;ItemData ItemOID="IT.RACE_BOOLEAN"&gt;&lt;Value&gt;false&lt;/Value&gt;&lt;/ItemData&gt;
                      &lt;/ItemGroupData&gt;
                   &lt;/ItemGroupData&gt;
                &lt;/ItemGroupData&gt;
             &lt;/StudyEventData&gt;
          &lt;/SubjectData&gt;
</code></pre>
<h2 id="heading-buscando-dados-de-uma-tag-apenas">Buscando dados de uma tag apenas</h2>
<p>Assim como podemos analisar como um documento XML inteiro está estruturado, é possível especificar uma tag e separar sua estrutura, podendo assim analisar como está disposta a prórpia tag, bem como as tags que estão ligadas a ela.</p>
<pre><code class="lang-python">print(etree.tostring(tree.find(<span class="hljs-string">'.//ItemData'</span>, ns), pretty_print = <span class="hljs-literal">True</span>, encoding = str))
</code></pre>
<pre><code class="lang-txt">    &lt;ItemData xmlns="http://www.cdisc.org/ns/odm/v2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlink="http://www.w3.org/1999/xlink" ItemOID="IT.DOB"&gt;
      &lt;Value&gt;1957-05-07&lt;/Value&gt;
    &lt;/ItemData&gt;
</code></pre>
<p>Agora, verifique a tag <code>Value</code>: ela possui um valor que nos interessa extrair, mas não está em um atributo; é um texto que está entre as tags. Para acessar o conteúdo que está entre as tags de abertura e fechamento, podemos nos valer da classe <code>text</code> do <code>lxml</code>.</p>
<pre><code class="lang-python">tree.find(<span class="hljs-string">'.//Value'</span>, ns).text
</code></pre>
<pre><code class="lang-txt">'1957-05-07'
</code></pre>
<p>O mesmo podemos fazer com o nome da tag, usando dessa vez a classe <code>tag</code>.</p>
<pre><code class="lang-python">tree.find(<span class="hljs-string">'.//Value'</span>, ns).tag
</code></pre>
<pre><code class="lang-txt">'{http://www.cdisc.org/ns/odm/v2.0}Value'
</code></pre>
<h2 id="heading-produzindo-planilhas">Produzindo planilhas</h2>
<p>Sabendo já alguns pontos básicos de XML, e como manipulá-los usando bibliotecas do Python, podemos agora ir para a fase seguinte: produzir planilhas (ou produzir DataFrames). Mas antes de fazermos isso, com o que já vimos, organizaremos um esquema de extração de dados usando o <code>lxml</code>.</p>
<p>O nosso objetivo aqui é elaborar um DataFrame que contenha os dados de <em>data de nascimento</em>, <em>sexo</em>, e <em>etnia</em> de cada indivíduo registrado no documento XML. Para tanto, adotaremos a estratégia de estabelecer um loop em <code>for</code>, para que, a cada iteração, consigamos extrair os dados associados à tag <code>SubjectData</code> e suas herdeiras. Feitas as iterações, armazenaremos os dados em uma lista <code>results</code>, cujo resultado aparece abaixo. É um método de resultado interessante, dado que os valores extraídos estão organizados em três grupos próprios, que serão as colunas do nosso futuro DataFrame.</p>
<pre><code class="lang-python">results = []
<span class="hljs-keyword">for</span> ide <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//SubjectData'</span>, ns):
    <span class="hljs-keyword">for</span> subj <span class="hljs-keyword">in</span> ide.findall(<span class="hljs-string">'.//StudyEventData/ItemGroupData/ItemGroupData/ItemData'</span>, ns):
            <span class="hljs-keyword">for</span> value <span class="hljs-keyword">in</span> subj:
                results.append([ide.attrib[<span class="hljs-string">'SubjectKey'</span>], subj.attrib[<span class="hljs-string">'ItemOID'</span>], value.text])

results
</code></pre>
<pre><code class="lang-txt">[['001', 'IT.DOB', '1957-05-07'],
['001', 'IT.SEX', '1'],
['001', 'IT.ETHNIC', '2'],
['002', 'IT.DOB', '1975-01-31&gt;'],
['002', 'IT.SEX', '2'],
['002', 'IT.ETHNIC', '2'],
['003', 'IT.DOB', '1961-06-09'],
['003', 'IT.SEX', '2'],
['003', 'IT.ETHNIC', '1']]
</code></pre>
<p>Elaborada a lista e armazenada na variável <code>results</code>, podemos agora facilmente usar o <code>pandas</code> para fazer um DataFrame, com a função <code>pd.DataFrame</code>. É fácil pois podemos utilizar a lista que produzimos diretamente, sem precisar de mais transformações. Nessa função, passaremos a lista como um argumento, e faremos menção aos nomes das colunas que queremos que apareça. São elas <code>ID</code>, <code>Variable</code>, <code>Value</code>. É possível, sem quaisquer problemas, colocar qualquer nome a cada coluna.</p>
<pre><code class="lang-python">results = pd.DataFrame(results, columns=[<span class="hljs-string">'ID'</span>, <span class="hljs-string">'Variable'</span>, <span class="hljs-string">'Value'</span>]) 
results
</code></pre>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td>ID</td><td>Variable</td><td>Value</td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td>001</td><td>IT.DOB</td><td>1957-05-07</td></tr>
<tr>
<td>1</td><td>001</td><td>IT.SEX</td><td>1</td></tr>
<tr>
<td>2</td><td>001</td><td>IT.ETHNIC</td><td>2</td></tr>
<tr>
<td>3</td><td>002</td><td>IT.DOB</td><td>1975-01-31&gt;</td></tr>
<tr>
<td>4</td><td>002</td><td>IT.SEX</td><td>2</td></tr>
<tr>
<td>5</td><td>002</td><td>IT.ETHNIC</td><td>2</td></tr>
<tr>
<td>6</td><td>003</td><td>IT.DOB</td><td>1961-06-09</td></tr>
<tr>
<td>7</td><td>003</td><td>IT.SEX</td><td>2</td></tr>
<tr>
<td>8</td><td>003</td><td>IT.ETHNIC</td><td>1</td></tr>
</tbody>
</table>
</div><p>Conseguimos um DataFrame, mas precisamos ir um pouco mais além antes de dar tudo como terminado. A ideia principal aqui é fazer com que <code>results</code> esteja com apenas um ID por linha, fazendo com que todos os dados referentes ao ID estejam nessa mesma linha. Aqui vemos que poderíamos utilizar os valores da coluna <code>Variable</code> como nomes das colunas, e o que está na coluna <code>Value</code> seriam os valores de cada coluna por ID.</p>
<p>A boa notícia é que o <code>pandas</code> permite fazer isso sem o menor problema. O que iremos performar agora é uma <em>pivotagem</em> dos dados que temos. Para tanto, podemos utilizar duas funções: <code>pivot</code> e <code>pivot_table</code>, com uma leve diferença entre as duas. A função escolhida aqui é a <code>pivot_table</code>, onde vamos lançar o <code>results</code> como fonte de dados, a coluns <code>ID</code> como índice temporário do DataFrame, a coluna <code>Value</code> como quem dará o nome às novas colunas, e a coluna <code>Value</code> como quem dará os valores às colunas. Ainda, teremos de invocar uma função no argumento <code>aggfunc</code>, que serve como uma função para fazer cálculos ou lançar um dado de forma ordenada (o primeiro dado a aparecer, o último, etc.). Nesse caso, usaremos a função <code>first</code>, porque simplesmente queremos que o primeiro (e único) valor a aparecer seja aquele aparente no DataFrame. Para fechar, utilizaremos o <code>reset_index</code>, fazendo com que <code>ID</code> volte a ser uma coluna manipulável.</p>
<pre><code class="lang-python">results = pd.pivot_table(results, index=<span class="hljs-string">'ID'</span>, columns=<span class="hljs-string">'Variable'</span>, values=<span class="hljs-string">'Value'</span>, aggfunc=<span class="hljs-string">'first'</span>).reset_index()
results
</code></pre>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Variable</td><td>ID</td><td>IT.DOB</td><td>IT.ETHNIC</td><td>IT.SEX</td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td>001</td><td>1957-05-07</td><td>2</td><td>1</td></tr>
<tr>
<td>1</td><td>002</td><td>1975-01-31&gt;</td><td>2</td><td>2</td></tr>
<tr>
<td>2</td><td>003</td><td>1961-06-09</td><td>1</td><td>2</td></tr>
</tbody>
</table>
</div><p>Assim estamos dando uma aparência mais definitiva ao nosso DataFrame. Mas veja que os nomes das colunas, bem como os valores das últimas duas planilhas ainda não nos informam com clareza qual a informação a ser mostrada. Analisando mais atentamente ao documento XML, se percebe que há uma parte nele que nos fornece informações valiosas para darmos mais sentido aos dados que temos: a parte dos <em>metadados</em>. É isso que exploraremos a partir de agora.</p>
<h2 id="heading-buscando-os-metadados-do-documento-xml-e-melhorando-a-planilha">Buscando os metadados do documento XML (e melhorando a planilha)</h2>
<p>Os metadados são as definições de cada variável e valor dentro do documento XML. É interessante, até preciso, obtê-los para que possamos compreender de fato o que cada coluna e valor representa em um DataFrame. Neste documento em específico, os metadados que nos interessam estão depositados nas tags de nome <code>ItemDef</code>, e podemos extraí-los com o bloco de código ilustrado abaixo:</p>
<pre><code class="lang-python"><span class="hljs-keyword">for</span> meta <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//ItemDef'</span>, ns):
    print(meta.attrib)
</code></pre>
<pre><code class="lang-txt">{'DataType': 'date', 'Name': 'Date of birth', 'OID': 'IT.DOB'}
{'DataType': 'integer', 'Length': '1', 'Name': 'Sex', 'OID': 'IT.SEX'}
{'DataType': 'integer', 'Length': '1', 'Name': 'Ethnicity', 'OID': 'IT.ETHNIC'}
{'OID': 'IT.RACE_CODE', 'Name': 'Race code', 'DataType': 'integer', 'Length': '1'}
{'DataType': 'boolean', 'Length': '1', 'Name': 'Race', 'OID': 'IT.RACE_BOOLEAN'}
{'DataType': 'text', 'Length': '20', 'Name': 'Other Race', 'OID': 'IT.RACEOTH'}
</code></pre>
<p>Perceba que o retorno é uma série de dicionários cujas chaves indicam aspectos como 'Nome' e 'OID' (um ID único para cada objeto que compõe o XML); para extrair esses dois e torná-los úteis para convertermos os nomes em código das colunas em um nome que nos indica o que determinada coluna realmente representa. Para tanto, criaremos um dicionário com o OID de cada coluna como chave, e o valor como o nome da coluna, como está abaixo:</p>
<pre><code class="lang-python">names = {}
<span class="hljs-keyword">for</span> meta <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//ItemDef'</span>, ns):
    names[meta.attrib[<span class="hljs-string">'OID'</span>]] = meta.attrib[<span class="hljs-string">'Name'</span>]
names
</code></pre>
<pre><code class="lang-txt">{'IT.DOB': 'Date of birth',
'IT.SEX': 'Sex',
'IT.ETHNIC': 'Ethnicity',
'IT.RACE_CODE': 'Race code',
'IT.RACE_BOOLEAN': 'Race',
'IT.RACEOTH': 'Other Race'}
</code></pre>
<p>Agora, com a função <code>rename</code> do pandas, podemos mudar os nomes das colunas em <code>results</code>, e as coisas começam a ter mais sentido.</p>
<pre><code class="lang-python">results = results.rename(columns=names)
results
</code></pre>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Variable</td><td>ID</td><td>Date of birth</td><td>Ethnicity</td><td>Sex</td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td>001</td><td>1957-05-07</td><td>2</td><td>1</td></tr>
<tr>
<td>1</td><td>002</td><td>1975-01-31&gt;</td><td>2</td><td>2</td></tr>
<tr>
<td>2</td><td>003</td><td>1961-06-09</td><td>1</td><td>2</td></tr>
</tbody>
</table>
</div><p>Nós temos aqui também duas colunas que estão em códigos numéricos: <code>Ethnicity</code> e <code>Sex</code>. As definições desses códigos, costumeiramente, estão no início do documento XML, junto dos metadados. Para obtermos os nomes dos códigos de sexo e etnia, nesse caso, há uma tag que será nosso alvo: <code>CodeList</code>. O código abaixo mostra como a tag está estruturada:</p>
<pre><code class="lang-python">print(etree.tostring(tree.find(<span class="hljs-string">'.//CodeList'</span>, ns), pretty_print = <span class="hljs-literal">True</span>, encoding = str))
</code></pre>
<pre><code class="lang-txt">    &lt;CodeList xmlns="http://www.cdisc.org/ns/odm/v2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlink="http://www.w3.org/1999/xlink" DataType="integer" Name="Sex" OID="CL.SEX"&gt;
                &lt;CodeListItem CodedValue="1"&gt;
                   &lt;Decode&gt;
                      &lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Male&lt;/TranslatedText&gt;
                   &lt;/Decode&gt;
                &lt;/CodeListItem&gt;
                &lt;CodeListItem CodedValue="2"&gt;
                   &lt;Decode&gt;
                      &lt;TranslatedText xml:lang="en" Type="text/plain"&gt;Female&lt;/TranslatedText&gt;
                   &lt;/Decode&gt;
                &lt;/CodeListItem&gt;
             &lt;/CodeList&gt;
</code></pre>
<p>Agora, dê uma recordada do método anterior que utilizamos para obter os nomes de colunas. Basicamente, o princípio para obter os valores dos códigos numéricos é o mesmo; contudo, ele é um pouco mais complexo, demandando um pouco mais de linhas de código. Ao acessar a tag <code>CodeList</code>, para o caso de querermos extrair os valores para <code>Ethnicity</code>, precisamos fazer uma filtragem mencionando o nome desse atributo, através do XPATH. Isso vem logo depois do nome da tag; assim sendo, podemos criar um novo dicionário, <code>ethnicity</code>, para abrigar códigos e valores para as etnias que estão representadas no DataFrame.</p>
<pre><code class="lang-python">ethnicity = {}
<span class="hljs-keyword">for</span> eth <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//CodeList[@Name="Ethnicity"]'</span>, ns):
    <span class="hljs-keyword">for</span> code <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//CodeList[@Name="Ethnicity"]/CodeListItem'</span>, ns):
        <span class="hljs-keyword">for</span> decode <span class="hljs-keyword">in</span> code:
            <span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> decode:
                ethnicity[code.attrib[<span class="hljs-string">'CodedValue'</span>]] = name.text
ethnicity
</code></pre>
<pre><code class="lang-txt">{'1': 'Hispanic', '2': 'Non-hispanic'}
</code></pre>
<p>Para obtermos os valores dos códigos da coluna <code>Sex</code>, basta usar o mesmo método anterior, apenas substituindo o nome do atributo a ser filtrado.</p>
<pre><code class="lang-python">sex = {}
<span class="hljs-keyword">for</span> eth <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//CodeList[@Name="Sex"]'</span>, ns):
    <span class="hljs-keyword">for</span> code <span class="hljs-keyword">in</span> tree.findall(<span class="hljs-string">'.//CodeList[@Name="Sex"]/CodeListItem'</span>, ns):
        <span class="hljs-keyword">for</span> decode <span class="hljs-keyword">in</span> code:
            <span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> decode:
                sex[code.attrib[<span class="hljs-string">'CodedValue'</span>]] = name.text
sex
</code></pre>
<pre><code class="lang-txt">{'1': 'Male', '2': 'Female'}
</code></pre>
<p>Dicionários preparados, podemos proceder às substituições que faltam. Aqui, usaremos a função do pandas <code>map</code>, que associa as chaves (i.e., os códigos numéricos) dos dicionários que criamos aos valores que dão nome aos números. Faremos isso para as duas colunas, <code>Ethnicity</code> e <code>Sex</code>; perceba que a planilha agora faz muito mais sentido, e está já pronta para fazer as análises que se deseja.</p>
<pre><code class="lang-python">results[<span class="hljs-string">'Ethnicity'</span>] = results[<span class="hljs-string">'Ethnicity'</span>].map(ethnicity)
results[<span class="hljs-string">'Sex'</span>] = results[<span class="hljs-string">'Sex'</span>].map(sex)
results
</code></pre>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Variable</td><td>ID</td><td>Date of birth</td><td>Ethnicity</td><td>Sex</td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td>001</td><td>1957-05-07</td><td>Non-hispanic</td><td>Male</td></tr>
<tr>
<td>1</td><td>002</td><td>1975-01-31&gt;</td><td>Non-hispanic</td><td>Female</td></tr>
<tr>
<td>2</td><td>003</td><td>1961-06-09</td><td>Hispanic</td><td>Female</td></tr>
</tbody>
</table>
</div><p>Para salvar o DataFrame que foi criado, por fim, basta usar as funções próprias do <code>pandas</code> para tanto. Assim as informações que foram extraídas estarão armazenadas em um arquivo mais leve e mais rápido de manipular.</p>
<pre><code class="lang-python"><span class="hljs-comment">## Exportando</span>

results.to_csv(<span class="hljs-string">'results.csv'</span>) <span class="hljs-comment">#Arquivo .csv</span>
results.to_excel(<span class="hljs-string">'results.xlsx'</span>) <span class="hljs-comment">#Arquivo .xlsx</span>
results.to_parquet(<span class="hljs-string">'results.parquet'</span>) <span class="hljs-comment">#Arquivo .parquet</span>
</code></pre>
<h2 id="heading-notas-do-artigo">Notas do artigo</h2>
<hr />
<p><span id="um"></span> 1. Isso é sucintamente e muito bem corroborado em Shabo et. al (2006): “The Clinical Data Interchange Standards Consortium (CDISC) is leading the development of standards to improve data quality and accelerate product development in the pharmaceutical industry.19 The CDISC model focuses on the use of metadata, and the approach is to combine XML representation with the tabular presentation traditionally used for clinical-trial data.”  - Shabo, A., S. Rabinovici-Cohen, e P. Vortman. “Revolutionary impact of XML on biomedical information interoperability”. IBM Systems Journal 45, nº 2 (2006): 361–72. https://doi.org/10.1147/sj.452.0361.
 <a class="post-section-overview" href="#um">↩</a></p>
<p><span id="dois"></span> 2. “Interest in ODM as a research topic has grown significantly over the last several years with increasing interest in the CDISC data standards from regulatory authorities such as the FDA and the Japanese Pharmaceutical and Medical Devices Agency (PMDA)” - Hume, Sam, Jozef Aerts, Surendra Sarnikar, e Vojtech Huser. “Current Applications and Future Directions for the CDISC Operational Data Model Standard: A Methodological Review”. Journal of Biomedical Informatics 60 (abril de 2016): 352–62. https://doi.org/10.1016/j.jbi.2016.02.016.
<a class="post-section-overview" href="#dois">↩</a></p>
<p><span id="tres"></span> 3. “While it is a requirement to submit pre-clinical and clinical data in CDISC format to regulatory bodies such as the US FDA and Japan’s Pharmaceuticals and Medical Devices Agency (PDMA), the actual usage of CDISC standards spans a much wider array of entities.” Hufstedler, Heather, Yannik Roell, Andressa Peña, Ankur Krishnan, Ian Green, Adriano Barbosa-Silva, Andreas Kremer, et al. “Navigating data standards in public health: A brief report from a data-standards meeting”. Journal of Global Health 14 ([s.d.]): 03024. https://doi.org/10.7189/jogh.14.03024.
 <a class="post-section-overview" href="#tres">↩</a></p>
<p><span id="quatro"></span> 4. "The CDISC Operational Data Model (ODM) is an XML format that facilitates the exchange of clinical data captured during a clinical study. ODMbased files contain the study data and the associated descriptions of the data items, their groupings into Case Report Forms (CRFs), which are electronic documents to record the study data, and the associated questions and code lists. Furthermore, the FDA has mandated the use of other CDISC standards in clinical studies." Leroux, Hugo, e Laurent Lefort. “Semantic Enrichment of Longitudinal Clinical Study Data Using the CDISC Standards and the Semantic Statistics Vocabularies”. Journal of Biomedical Semantics 6, nº 1 (dezembro de 2015): 16. https://doi.org/10.1186/s13326-015-0012-6. <a class="post-section-overview" href="#quatro">↩</a></p>
<p><span id="cinco"></span> 5. “The Federal Drug Administration has mandated the use of the CDISC standards for the electronic capture and reporting of clinical study data” Leroux, Hugo, Alejandro Metke-Jimenez, e Michael J. Lawley. “Towards Achieving Semantic Interoperability of Clinical Study Data with FHIR”. Journal of Biomedical Semantics 8, nº 1 (19 de setembro de 2017): 41. https://doi.org/10.1186/s13326-017-0148-7. <a class="post-section-overview" href="#cinco">↩</a></p>
<p><span id="seis"></span> 6. Lefort, Laurent, e Hugo Leroux. “Design and generation of Linked Clinical Data Cubes”, 2013. https://doi.org/10.13140/RG.2.1.3677.2967. <a class="post-section-overview" href="#seis">↩</a></p>
<p><span id="sete"></span> 7. Brix, Tobias Johannes, Philipp Bruland, Saad Sarfraz, Jan Ernsting, Philipp Neuhaus, Michael Storck, Justin Doods, Sonja Ständer, e Martin Dugas. “ODM Data Analysis—A Tool for the Automatic Validation, Monitoring and Generation of Generic Descriptive Statistics of Patient Data”. PLOS ONE 13, nº 6 (22 de junho de 2018): e0199242. https://doi.org/10.1371/journal.pone.0199242. <a class="post-section-overview" href="#sete">↩</a></p>
<p><span id="oito"></span> 8. <strong>Uma nota importante</strong>: A partir de agora, além das bibliotecas Python, e do XML, nos valeremos de uma outra linguagem, esta de consulta: o <em>XPath</em>. Com ela, podemos acessar de forma apropriada os elementos e atributos do XML. Não entrarei em detalhes sobre ela neste artigo; mas, caso você queira entender melhor do que se trata, você pode ver mais detalhes <a target="_blank" href="https://escoladedados.org/tutoriais/xpath-para-raspagem-de-dados-em-html/">aqui</a> e <a target="_blank" href="https://www.w3schools.com/xml/xpath_intro.asp">aqui</a>, além de um bom cheatsheet <a target="_blank" href="https://devhints.io/xpath">aqui</a>. Não usaremos muitas coisas diferentes dessa linguagem por aqui, mas é interessante ir mais a fundo depois. <a class="post-section-overview" href="#oito">↩</a></p>
<hr />
]]></content:encoded></item><item><title><![CDATA[Aula 10.1 - Análise e visualização de dados em Python - biblioteca pandas (parte 6)]]></title><description><![CDATA[Pense se você já se deparou alguma vez com as seguintes situações:

Os dados que chegam a você para análises estão divididos em duas ou mais tabelas;

Você precisa dividir o conteúdo de uma tabela em dois para poder processar melhor os dados... e dep...]]></description><link>https://blog.matheusyuri.pro/aula-101-analise-e-visualizacao-de-dados-em-python-biblioteca-pandas-parte-6</link><guid isPermaLink="true">https://blog.matheusyuri.pro/aula-101-analise-e-visualizacao-de-dados-em-python-biblioteca-pandas-parte-6</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[data]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Tue, 26 Oct 2021 17:04:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1635267351719/1NrcNZgYE.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Pense se você já se deparou alguma vez com as seguintes situações:</p>
<ul>
<li><p>Os dados que chegam a você para análises estão divididos em duas ou mais tabelas;</p>
</li>
<li><p>Você precisa dividir o conteúdo de uma tabela em dois para poder processar melhor os dados... e depois precisa os juntar outra vez, ou precisa fazer uma análise com uma parte da primeira tabela, e outra parte da segunda;</p>
</li>
<li><p>E nessas duas situações, você não tem ideia do que fazer, além de juntar tudo manualmente, no <code>Ctrl+C</code>, <code>Ctrl+V</code>, sempre se sujeitando a errar em algo.</p>
</li>
</ul>
<p>Essas situações podem gerar um desperdício de tempo, energia, e dinheiro considerável, sem falar no desespero que pode bater. Então, sendo uma biblioteca completa para análise de dados, o pandas também providencia funções para agregação de diferentes <em>dataframes</em>, sendo soluções fáceis e bastante práticas. A <a target="_blank" href="https://pandas.pydata.org/pandas-docs/stable/user_guide/merging.html">documentação da biblioteca</a> mostra com detalhes as possibilidades para fazer essas combinações, e é esse aspecto do pandas que exploraremos nessa aula.</p>
<p>Então, o que será visto aqui:</p>
<ul>
<li><p>Como combinar <em>dataframes</em> com a biblioteca pandas;</p>
</li>
<li><p>Principais funções do pandas para concatenar, unir, e juntar.</p>
</li>
</ul>
<h2 id="heading-combinar-dataframes-com-o-pandas">Combinar <em>dataframes</em> com o pandas</h2>
<p>A documentação do pandas, especialmente no <a target="_blank" href="https://pandas.pydata.org/pandas-docs/stable/user_guide/merging.html#comparing-objects">Guia do Usuário</a>, indica que temos, pelo menos, três modos de combinar conjuntos de dados: com concatenação (<code>concat()</code>), união (<code>merge()</code>), e a junção (<code>join()</code>). Para usar essas funções, é preciso levar em consideração duas coisas: o que você quer juntar de duas ou mais tabelas, e onde você quer chegar com isso. Caso isso tenha ficado confuso por agora, não se preocupe, pois à medida em que as funções e suas capacidades forem apresentadas, você poderá já identificar qual a função que vem de encontro ao seu objetivo, e como usá-la para conseguir aquilo que se quer.</p>
<h3 id="heading-antes-de-mais-nada-carregando-os-datasets-para-uso-no-pandas">Antes de mais nada: carregando os <em>datasets</em> para uso no pandas</h3>
<p>Como essa série é baseada na mistura entre partes teóricas e práticas, antes de irmos à parte de apresentação das funções, precisamos carregar os conjuntos de dados com os quais iremos trabalhar aqui. Esses conjuntos estão no <a target="_blank" href="https://github.com/mhalmenschlager/python-biologia">repositório da série no GitHub</a>, para que você possa os usar livremente. E como carregaremos mais de um conjunto, faremos aqui uma coisa diferente: em vez de apenas nomear o objeto atribuído ao conjunto de dados apenas como <code>df</code>, usaremos os nomes de cada arquivo <code>.csv</code> disponibilizados. No caso, portanto, os objetos serão nomeados <code>surveys</code> e <code>species</code>, sendo que o processo de nomeação é o mesmo que utilizamos para <code>df</code>.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd <span class="hljs-comment">#Importação da biblioteca pandas (sempre a primeira coisa a ser feita)</span>
surveys = pd.read_csv(<span class="hljs-string">"https://github.com/mhalmenschlager/python-biologia/raw/main/archives/surveys.csv"</span>) <span class="hljs-comment">#Carrega o arquivo 'surveys.csv'</span>
species = pd.read_csv(<span class="hljs-string">"https://github.com/mhalmenschlager/python-biologia/raw/main/archives/species.csv"</span>) <span class="hljs-comment">#Carrega o arquivo 'species.csv'</span>
</code></pre>
<p>Isso posto, agora podemos começar a entender como as funções <code>concat()</code>, <code>merge()</code>, e <code>join()</code> funcionam. Para tanto, a aula será dividida em três posts ou partes diferentes:</p>
<ul>
<li><p>A primeira parte, que vem a seguir, apresenta a função <code>concat()</code>;</p>
</li>
<li><p>A segunda parte discute sobre a função <code>join()</code>;</p>
</li>
<li><p>A terceira e última parte será dedicada à função <code>merge()</code>.</p>
</li>
</ul>
<h3 id="heading-concatenacao-funcao-concathttpspandaspydataorgpandas-docsstablereferenceapipandasconcathtml">Concatenação: função <a target="_blank" href="https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.concat.html"><code>concat()</code></a></h3>
<p>A função de concatenação é considerada o 'canivete suíço' das funções de combinação de <em>dataframes</em>, <a target="_blank" href="https://realpython.com/pandas-merge-join-and-concat/#pandas-concat-combining-data-across-rows-or-columns">podendo operar tanto com linhas, quanto com colunas</a>. A questão aqui é que os <em>dataframes</em> a serem selecionados para a operação serão apenas "colados", seja pelo eixo de suas linhas, ou pelo eixo de suas colunas.</p>
<p>Para entender melhor, façamos o seguinte: a partir do <em>dataframe</em><code>surveys</code> criado anteriormente, criemos dois outros, com as cinco primeiras entradas e as cinco últimas entradas desse conjunto. Assim:</p>
<pre><code class="lang-python">surveys_primeiras = surveys.head() <span class="hljs-comment">#Cinco primeiras entradas de 'surveys'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1635267452830/Z7NBLvvIk.png" alt="image-20211025200735015.png" /></p>
<pre><code class="lang-python">surveys_ultimas = surveys.tail() <span class="hljs-comment">#Cinco últimas entradas de 'surveys'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1635267496969/XbKcIM9hx.png" alt="image-20211025200836762.png" /></p>
<blockquote>
<p>**Um detalhe: **Se você executar os blocos de código que foram até agora aqui expostos, poderá perceber uma coisa: ao criarmos os novos objetos, a tabela <code>surveys_ultimas</code> mantém a indexação da tabela da qual se originou. Caso queiramos que haja uma indexação nova, há uma função para isso: <a target="_blank" href="https://www.w3schools.com/python/pandas/ref_df_reset_index.asp"><code>reset.index()</code></a>. Usamos ela da seguinte forma:</p>
<pre><code class="lang-python">surveys_ultimas = surveys_ultimas.reset_index(drop=<span class="hljs-literal">True</span>) <span class="hljs-comment">#Reorganiza o índice de 'surveys_ultimas', trocando o índice antigo de 'surveys' para um novo.</span>
</code></pre>
<p>Esta função será mencionada outras vezes nessa aula, uma vez que ela será importante para que possamos fazer o processo de concatenação de forma correta em um dado momento.</p>
</blockquote>
<p>Tendo esses novos objetos em mãos, podemos fazer a operação de concatenação, seja ela vertical (colados pelo eixo das colunas), ou horizontal (colados pelo eixo das linhas), usando a função <code>concat()</code>.</p>
<pre><code class="lang-python">vertical = pd.concat([surveys_primeiras, surveys_ultimas], axis=<span class="hljs-number">0</span>) <span class="hljs-comment">#Concatenação vertical</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1635267699588/N8DJJUWHk.png" alt="image-20211025201021705.png" /></p>
<pre><code class="lang-python">horizontal = pd.concat([surveys_primeiras, surveys_ultimas], axis=<span class="hljs-number">1</span>) <span class="hljs-comment">#Concatenação horizontal</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1635267734878/xAARkuR-9.png" alt="image-20211025201510548.png" /></p>
<p>Repare que, quando a função <code>concat()</code>é chamada, há um parâmetro que indica por qual eixo queremos fazer a concatenação, o <code>axis</code>. Então, para que a operação corra bem, lembre-se sempre de que, para fazer a operação vertical, o <a target="_blank" href="https://stackoverflow.com/questions/22149584/what-does-axis-in-pandas-mean"><code>axis</code> possui valor <code>0</code>; para a horizontal, valor <code>1</code></a>. Ainda, precisamos sempre reparar se as coisas estão fazendo sentido: ao fazermos a concatenação horizontal, os dados contidos nas linhas a serem coladas precisam estar relacionados de alguma forma. Na concatenação vertical, é imperativo verificar se as colunas possuem as mesmas características, i.e., o mesmo nome e o mesmo tipo de dado.</p>
<blockquote>
<p><strong>Um detalhe:</strong> Quando fazemos a concatenação vertical, podemos passar por um pequeno problema: os índices das linhas não tem continuidade, pulando do índice 4 para o 35544 de uma vez só. Isso acontece porque colamos linhas e colunas de <em>dataframes</em> com seus próprios índices. Um modo de contornar o problema é utilizar a função <code>reset_index()</code> (olha ela aqui de novo!) para que o índice seja reorganizado. Assim:</p>
<pre><code class="lang-python">vertical = vertical.reset_index() <span class="hljs-comment">#Reseta o índice</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1635267667646/m6YA5fHV4.png" alt="image-20211026091342520.png" /></p>
<p>Perceba que a indexação agora aparece organizada.</p>
<p><strong>Outro detalhe:</strong> Não parece que a concatenação horizontal ficou parecendo uma bagunça, cheia de <code>NaN</code>? Isso aconteceu por um motivo simples: quando as tabelas são colocadas lado a lado, as identificações das colunas podem se repetir, e as linhas acabam por ganhar 'extensões'; como não há dados nessas novas células, elas aparecem como dados nulos. Para resolver essa 'zona', podemos utilizar o <code>reset_index()</code>mais uma vez. Nesse caso, podemos criar um novo objeto com o índice resetado, e fazermos a concatenação outra vez. Assim:</p>
<pre><code class="lang-python">surveys_ultimas2 = surveys_ultimas.reset_index(drop=<span class="hljs-literal">True</span>) <span class="hljs-comment">#Cria um novo objeto, 'surveys_ultimas2', com o índice resetado</span>
horizontal_2 = pd.concat([surveys_primeiras, surveys_ultimas2], axis=<span class="hljs-number">1</span>) <span class="hljs-comment">#Faz concatenação horizontal, com as duas tabelas tendo mesmo índice</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1635267778160/LlEzgl7J5.png" alt="image-20211026091721742.png" /></p>
<p>Agora sim, temos uma concatenação horizontal mais bem organizada do que a anterior.</p>
</blockquote>
<hr />
<p>A função <code>concat()</code> é uma excelente função para a união de dois ou mais <em>dataframes</em> baseando-se em suas indexações, uma vez que pode trabalhar tanto com o eixo das linhas, quanto o das colunas, se transformando no 'canivete suíço' das funções que usam o índice como base. O que foi apresentado aqui é uma parte mais básica da função, com a qual você já pode sair praticando com outras bases de dados; <code>concat()</code> possui mais detalhes em seus argumentos, fazendo com que valha a pena analisar a documentação e outras referências para ter noção do poder dessa função no que se refere a juntar conjuntos de dados.</p>
<p>Aproveite para praticar a função <code>concat()</code>e nos vemos nas próximas partes, onde discutiremos mais sobre <code>merge()</code>, outra formas de juntar conjuntos de dados.</p>
<p>Um grande abraço e até o próximo post!</p>
<hr />
<p><strong>Para ler mais:</strong></p>
<ul>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/53645882/pandas-merging-101"><strong>Pandas Merging 101 - StackOverflow</strong></a></p>
</li>
<li><p><a target="_blank" href="https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.concat.html"><strong>pandas.concat - Documentação do pandas</strong></a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/49620538/what-are-the-levels-keys-and-names-arguments-for-in-pandas-concat-functio/49620539#49620539"><strong>What are the 'levels', 'keys', and names arguments for in Pandas' concat function? - Stack Overflow</strong></a></p>
</li>
<li><p><a target="_blank" href="https://towardsdatascience.com/python-pandas-dataframe-join-merge-and-concatenate-84985c29ef78"><strong>Python Pandas DataFrame Join, Merge, and Concatenate - Towards Data Science</strong></a></p>
</li>
<li><p><a target="_blank" href="https://towardsdatascience.com/practical-uses-of-merge-join-and-concat-8f011bbac241"><strong>Practical uses of merge, join and concat - Towards Data Science</strong></a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Aula 9 - Análise e visualização de dados com Python - biblioteca pandas (parte 5)]]></title><description><![CDATA[Quando acessamos algumas bases de dados e colocamos as mãos em datasets para treinar nossas habilidades de análise e visualização de dados, seja em Python, ou em qualquer outra linguagem ou ferramenta, geralmente nos deparamos em dados que já passara...]]></description><link>https://blog.matheusyuri.pro/aula-9-analise-e-visualizacao-de-dados-com-python-biblioteca-pandas-parte-5</link><guid isPermaLink="true">https://blog.matheusyuri.pro/aula-9-analise-e-visualizacao-de-dados-com-python-biblioteca-pandas-parte-5</guid><category><![CDATA[Python]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[data]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Mon, 27 Sep 2021 19:10:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1632768895051/aDkxriXpg.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Quando acessamos algumas bases de dados e colocamos as mãos em <em>datasets</em> para treinar nossas habilidades de análise e visualização de dados, seja em Python, ou em qualquer outra linguagem ou ferramenta, geralmente nos deparamos em dados que já passaram por um processo que chamamos de <a target="_blank" href="https://www.tableau.com/learn/articles/what-is-data-cleaning"><em>data cleaning</em></a>, ou, em português, <a target="_blank" href="https://www.ibpad.com.br/blog/comunicacao-digital/uma-visao-geral-sobre-a-limpeza-dos-dados/"><strong>limpeza de dados</strong></a>. Esse processo é essencial quando vamos trabalhar com dados, sendo o que mais nos demanda atenção: boa parte do tempo de um analista é ocupado com limpeza, transformação e reorganização daquele monte de dados entulhados em algum lugar (há pessoas que dizem que essa parte <a target="_blank" href="https://www.projectpro.io/article/why-data-preparation-is-an-important-part-of-data-science/242">ocupa até 80% do tempo!</a> Outros dizem que <a target="_blank" href="https://blog.ldodds.com/2020/01/31/do-data-scientists-spend-80-of-their-time-cleaning-data-turns-out-no/">não é bem assim</a>...). Então, os dados que usualmente utilizamos para treinar, e que estão disponíveis em plataformas como o <a target="_blank" href="https://kaggle.com">Kaggle</a> estão limpos e organizados.</p>
<p>No entanto, quando nos deparamos com <em>datasets</em> do mundo real, inclusive aqueles que nós mesmos coletamos, percebemos que eles correm o grande risco de <a target="_blank" href="https://jakevdp.github.io/PythonDataScienceHandbook/03.04-missing-values.html">não serem completos e padronizados</a>, fazendo com que todo aquele tempo com limpeza dos dados acabe por ocorrer conosco também. <a target="_blank" href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3668100/"><strong>Mesmo com o processo de coleta e ingestão de dados mais rigoroso, mais cuidadoso possível, todo conjunto de dados está suscetível a alguma "sujeira"</strong></a>. Por isso mesmo, é essencial aprender a detectar as inconsistências nos dados que podemos encontrar, e, sobretudo, saber o que fazer com elas.</p>
<p>Essa aula é dedicada a uma parte do processo de limpeza de dados, com exemplo e recomendação do que fazer quando você se deparar com aquilo que se costuma chamar <strong>dados nulos</strong>. </p>
<p>Então, eis o que veremos aqui:</p>
<ul>
<li>O que são dados nulos (e por que eles aparecem);</li>
<li>Como detectar dados nulos;</li>
<li>Como lidar com dados nulos.</li>
</ul>
<h2 id="afinal-o-que-sao-dados-nulos-e-por-que-eles-aparecem">Afinal, o que são dados nulos (e por que eles aparecem?)</h2>
<p><strong>Dados nulos</strong> ou <a target="_blank" href="https://pt.wikipedia.org/wiki/N%C3%A3o-resposta">não-respostas</a> (<a target="_blank" href="https://en.wikipedia.org/wiki/Missing_data"><em>missing values</em></a>, em inglês) são os dados que, por alguma circunstância, não estão disponíveis para análise. A origem deles pode ser variada, e aqui cita-se alguns exemplos:</p>
<ul>
<li>Erros de digitação/transcrição para o banco de dados (ou seja, na ingestão desses dados);</li>
<li>Esquecimento da coleta de uma determinada variável em um momento específico;</li>
<li>Adição ou subtração de variáveis no decorrer do processo de coleta de dados (especialmente aquelas coletas que levam anos a serem feitas);</li>
<li>Falta de uma padronização na organização dos dados.</li>
</ul>
<blockquote>
<p><strong>NOTA:</strong> Para entender mais sobre os tipos de dados nulos e como eles aparecem, recomendo algumas referências: os artigos de <a target="_blank" href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3668100/">Kang (2013)</a> e <a target="_blank" href="https://pubmed.ncbi.nlm.nih.gov/23853744/">Dong e Peng (2013)</a>, além do verbete sobre <em>missing data</em> na <a target="_blank" href="https://en.wikipedia.org/wiki/Missing_data">Wikipédia em inglês</a> e <a target="_blank" href="https://pt.wikipedia.org/wiki/N%C3%A3o-resposta">em português</a>.</p>
</blockquote>
<p>A presença de dados nulos, apesar de ser comum, <a target="_blank" href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5548942/">pode afetar a análise dos dados, reduzindo seu poder estatístico e explicativo</a>. Por isso mesmo, é bastante importante não ignorá-los; A seguir veremos como podemos detectar esses dados nulos no <em>dataset</em> com o qual estamos trabalhando.</p>
<h3 id="como-detectar-dados-nulos">Como detectar dados nulos</h3>
<p>A detecção de dados nulos no pandas é bem simples, e normalmente é um das primeiras coisas ao se trabalhar com essa biblioteca. Na documentação do pandas, há um guia chamado <a target="_blank" href="https://pandas.pydata.org/pandas-docs/stable/user_guide/missing_data.html">"Working with missing data"</a>, onde funções relacionadas com dados nulos são apresentadas. Com o mesmo <em>dataframe</em> que estamos utilizando desde o início da parte prática da série, exploraremos aqui algumas funções (algumas citadas nesse guia) para detectar dados nulos.</p>
<h4 id="funcoes-heade-tail">Funções <code>head()</code>e <code>tail()</code></h4>
<p>Com as funções que usualmente iniciamos os nossos passos para análise de dados dentro da linguagem Python com o pandas, já é possível observar uma possível existência de dados nulos. Usando <code>head()</code> e <code>tail()</code>, podemos verificar se as primeiras e as últimas linhas da tabela possuem células preenchidas com <code>NaN</code>, <code>NaT</code>, ou <code>None</code>.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd <span class="hljs-comment">#Sempre importe o pandas antes de começar</span>
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np <span class="hljs-comment">#Sempre bom importar o Numpy também</span>

df = pd.read_csv(<span class="hljs-string">"https://github.com/mhalmenschlager/python-biologia/raw/main/archives/surveys.csv"</span>) <span class="hljs-comment">#Nosso dataset de exemplo. Importe-o no seu notebook ou IDE de preferência</span>
df.head() <span class="hljs-comment">#Cinco primeiras entradas</span>
df.tail() <span class="hljs-comment">#Cinco últimas entradas</span>
</code></pre>
<h4 id="funcao-info">Função <code>info()</code></h4>
<p>A função <code>info()</code>, que já foi vista por aqui, é uma das funções que podem ser utilizadas para observar a existência de dados nulos, através da análise de cada coluna/variável no <em>dataframe</em>. Essa função retorna uma lista com a quantidade de células em cada variável que possua dados válidos (<code>non-null</code>); é possível, a partir daí, comparar os números de células com dados válidos com o número total de linhas e colunas de <code>df</code>.</p>
<pre><code class="lang-python">df.info() <span class="hljs-comment">#Observação de dados não-nulos</span>
</code></pre>
<h4 id="funcao-isnullhttpspandaspydataorgdocsreferenceapipandasdataframeisnullhtml">Função <a target="_blank" href="https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.isnull.html"><code>isnull()</code></a></h4>
<p>A resposta da função é um indicador booleano: para dados nulos, aparece o <code>True</code>, enquanto que para os dados não-nulos, é o <code>False</code>quem surge. Você pode utilizá-la junto da função <code>sum()</code>para quantificar os dados nulos de uma determinada coluna, por exemplo.</p>
<pre><code class="lang-python">df.isnull() <span class="hljs-comment">#Dados nulos (com retorno booleano) de todo o dataframe</span>
df.column.isnull() <span class="hljs-comment">#Dados nulos de uma variável</span>
df.column.isnull().sum() <span class="hljs-comment">#Soma de células com dados nulos em uma variável</span>
nulo = df.isnull().sum().sort_values(ascending=<span class="hljs-literal">False</span>) <span class="hljs-comment">#Verificação de dados nulos, em ordem decrescente</span>
(nulo / df.shape[<span class="hljs-number">0</span>])*<span class="hljs-number">100</span> <span class="hljs-comment">#Verificação de porcentagem de dados nulos por variável</span>
</code></pre>
<h4 id="funcao-notnullhttpspandaspydataorgpandas-docsstablereferenceapipandasnotnullhtml">Função <a target="_blank" href="https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.notnull.html"><code>notnull()</code></a></h4>
<p>A função <code>notnull()</code>, assim como a função <code>isnull()</code>, retorna um valor booleano, apenas aqui sendo o contrário: o <code>True</code>aparece para dados não-nulos. Usando a função <code>sum()</code>, o retorno também será quantitativo, com resultado semelhante à função <code>info()</code>, com a diferença da possibilidade de quantificação de uma só coluna.</p>
<pre><code class="lang-python">df.notnull() <span class="hljs-comment">#Dados válidos (com retorno booleano) de todo o dataframe</span>
df.column.notnull() <span class="hljs-comment">#Dados válidos (com retorno booleano) de uma variável</span>
df.column.notnull().sum() <span class="hljs-comment">#Soma de células de uma variável com dados válidos</span>
<span class="hljs-comment">### Usando as funções para criar novos objetos ###</span>
valido = df.notnull().sum().sort_values(ascending=<span class="hljs-literal">False</span>) <span class="hljs-comment">#Verificação de dados válidos, em ordem decrescente</span>
(valido / df.shape[<span class="hljs-number">0</span>])*<span class="hljs-number">100</span> <span class="hljs-comment">#Verificação de porcentagem de dados nulos por variável</span>
</code></pre>
<h4 id="funcoes-isnahttpspandaspydataorgdocsreferenceapipandasisnahtml-e-notnahttpspandaspydataorgpandas-docsstablereferenceapipandasnotnahtml">Funções <a target="_blank" href="https://pandas.pydata.org/docs/reference/api/pandas.isna.html"><code>isna()</code></a> e <a target="_blank" href="https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.notna.html"><code>notna()</code></a></h4>
<p>Outro conjunto de funções que pode ser utilizado para verficiar a presença de dados nulos e que aparece na documentação do pandas é o composto por <code>isna()</code> e <code>notna()</code>. Essas funções são semelhantes a <code>isnull()</code> e <code>notnull()</code>, respectivamente, dando um retorno booleano ao processo de verificação.</p>
<pre><code class="lang-python">df.isna() <span class="hljs-comment">#Dados nulos (com retorno booleano) de todo o dataframe</span>
df.notna() <span class="hljs-comment">#Dados válidos (com retorno booleano) de todo o dataframe</span>
</code></pre>
<h3 id="como-lidar-com-dados-nulos">Como lidar com dados nulos?</h3>
<p>Existem diversas formas de fazer um processo de manipulação de dados para contornar o problema dos dados nulos; isso depende, portanto, da capacidade de discernimento do pesquisador ao definir qual é a melhor maneira a ser adotada. Tal capacidade vem com a compreensão do conjunto de dados (saber o que são as variáveis a serem analisadas, qual o peso delas para as análises a serem feitas...) e, principalmente, qual o problema a ser resolvido ou a pergunta que se quer responder com aquilo que foi coletado. Nessa parte da aula, veremos algumas funções do pandas que nos ajudam a fazer a "contenção de danos" ao lidarmos com a "sujeira" dos nossos dados.</p>
<h4 id="funcao-dropnahttpspandaspydataorgpandas-docsstablegeneratedpandasdataframedropnahtml">Função <a target="_blank" href="https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dropna.html"><code>dropna()</code></a></h4>
<p>A função <code>dropna()</code>tem como objetivo retirar linhas ou colunas que contenham, pelo menos, um valor nulo. Por padrão, a função sozinha elimina todas as linhas, mas isso pode ser alterado de acordo com os argumentos que são passados na linha de código.</p>
<pre><code class="lang-python">df.dropna() <span class="hljs-comment">#Elimina todas as linhas que possuam qualquer dado nulo</span>
df.dropna(axis=<span class="hljs-number">1</span>) <span class="hljs-comment">#Elimina todas as colunas que possuam qualquer dado nulo</span>
df.dropna(axis=<span class="hljs-number">0</span>, have=<span class="hljs-string">'any'</span>) <span class="hljs-comment">#Elimina todas as linhas que possuam qualquer dado nulo</span>
df.dropna(axis=<span class="hljs-number">0</span>, have=<span class="hljs-string">'all'</span>) <span class="hljs-comment">#Elimina todas as linhas que possuam todos os valores como dados nulos</span>
df.dropna(axis=<span class="hljs-number">0</span>, thresh=<span class="hljs-number">2</span>) <span class="hljs-comment">#Mantém linhas que possuam, no máximo, 2 valores como dados nulos, eliminando as demais</span>
</code></pre>
<h4 id="funcao-fillnahttpspandaspydataorgpandas-docsstablegeneratedpandasdataframefillnahtml">Função <a target="_blank" href="https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.fillna.html"><code>fillna()</code></a></h4>
<p>Se a função <code>dropna()</code>serve para, simplesmente, eliminar dados nulos, a função <code>fillna()</code> serve para mantê-los, fazendo um processo de preenchimento das células que apresentam valores como <code>NA</code>, <code>NaN</code>, ou <code>NaT</code>. Para preenchimento efetivo, é necessário especificar o método a ser adotado, passando argumentos ao código que será executado.</p>
<pre><code class="lang-python">df.fillna(<span class="hljs-number">0</span>) <span class="hljs-comment">#Preenche todos os elementos NaN com o valor 0</span>
df.fillna(method=<span class="hljs-string">'pad'</span>) <span class="hljs-comment">#Preenche os elementos NaN com a última observação válida</span>
df.fillna(method=<span class="hljs-string">'ffill'</span>) <span class="hljs-comment">#Preenche os elementos NaN com a última observação válida</span>
df.fillna(method=<span class="hljs-string">'bfill'</span>) <span class="hljs-comment">#Preenche os elementos NaN com a observação válida posterior a eles</span>
df.fillna(method=<span class="hljs-string">'backfill'</span>) <span class="hljs-comment">#Preenche os elementos NaN com a observação válida posterior a eles</span>
df.fillna(value=<span class="hljs-number">0</span>, limit=<span class="hljs-number">1</span>) <span class="hljs-comment">#Preenche apenas o primeiro elemento NaN do dataframe com o valor 0</span>

<span class="hljs-comment">#### Usando índices de tendência central ####</span>

df[<span class="hljs-string">'column'</span>].fillna(int(mean), inplace=<span class="hljs-literal">True</span>) <span class="hljs-comment">#Preenche elementos NaN com a média</span>
df[<span class="hljs-string">'column'</span>].fillna(int(median), inplace =<span class="hljs-literal">True</span>) <span class="hljs-comment">#Preenche elementos NaN com a mediana</span>
df[<span class="hljs-string">'column'</span>].fillna(int(mode), inplace=<span class="hljs-literal">True</span>) <span class="hljs-comment">#Preenche elementos NaN com a moda</span>
</code></pre>
<h4 id="funcao-interpolatehttpspandaspydataorgdocsreferenceapipandasdataframeinterpolatehtml">Função <a target="_blank" href="https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.interpolate.html"><code>interpolate()</code></a></h4>
<p>Quando as medidas de tendência central não parecem ser suficientes para preencher o espaço dos valores nulos num <em>dataframe</em>, é possível lançar mão do método chamado de <strong>interpolação</strong>. Basicamente, interpolar é gerar um dado novo a partir de um conjunto de dados que já são conhecidos. Nesse caso, o pandas pode usar os valores vizinhos de uma célula cujo valor ainda não é conhecido aqui (<code>NaN</code>) para estimar um valor novo que pareça fazer mais sentido àquele conjunto de dados que estamos analisando. A função de interpolação é semelhante ao <code>fillna()</code>, mas com a diferença é que é muito mais flexível; ao usar <code>interpolate()</code>, o analista possui uma variedade interessante de interpolações à mão, sendo que a interpolação padrão por parte do pandas é a do tipo <code>linear</code>. Algumas dessas interpolações podem ser vistas no exemplo abaixo:</p>
<pre><code class="lang-python">df.interpolate() <span class="hljs-comment">#Interpolação do tipo linear para os valores nulos do dataframe</span>
df.interpolate(method=<span class="hljs-string">'polynomial'</span>, order=<span class="hljs-number">2</span>) <span class="hljs-comment">#Interpolação do tipo polinomial para os valores nulos do dataframe</span>
df.interpolate(method=<span class="hljs-string">'pad'</span>, limit=<span class="hljs-number">2</span>) <span class="hljs-comment">#Interpolação com preenchimento com o valor acima do valor nulo, com limite de 2 valores NaN</span>
df.interpolate(method=<span class="hljs-string">'linear'</span>, limit_direction=<span class="hljs-string">'forward'</span>) <span class="hljs-comment">#Interpolação do tipo linear para os valores nulos do dataframe utilizando o valor anterior como limite</span>
df.interpolate(method =<span class="hljs-string">'linear'</span>, limit_direction =<span class="hljs-string">'backward'</span>, limit = <span class="hljs-number">1</span>) <span class="hljs-comment">#Interpolação do tipo linear para os valores nulos do dataframe utilizando o valor posterior ao NaN como limite, sendo 1 o número máximo de valores NaN que podem ser preenchidos com esse método</span>
</code></pre>
<blockquote>
<p> E agora, <strong>Que tal fazer você mesmo?</strong></p>
<p>Com todos os códigos em mãos, aproveite apara abrir um novo arquivo <code>.ipynb</code> ou <code>.py</code>no Google Colab, no Anaconda ou em outra IDE que você conheça, e vá explorando os blocos de código aqui citados, tanto com o <em>dataset</em> de exemplo, quanto o seu próprio conjunto de dados, ou algum outro que você viu na Internet ou que passaram para você treinar.</p>
</blockquote>
<hr />
<p>Ao terminar essa aula, recomendo a você que dê uma olhada na documentação do pandas e nas referências que estão nos hyperlinks e na seção 'Para ler mais' abaixo para entender bem essa parte de verificar dados nulos e lidar com eles. Por ser um processo que se inclui na limpeza de dados, é uma das mais importantes ações que é preciso fazer ao lidar com análise e visualização de dados, e as aplicações posteriores a isso. Não se esqueça também de praticar exaustivamente com os códigos aqui passados, para absorver todo o potencial de cada função do pandas explanada aqui.</p>
<p>Então, cuide bem dos seus dados! Economiza tempo, energia e, dependendo do caso, até dinheiro...</p>
<p>Um grande abraço, divirta-se com os códigos e até a próxima aula!</p>
<hr />
<p><strong>Para ler mais:</strong></p>
<ul>
<li><strong><a target="_blank" href="https://minerandodados.com.br/manipulando-missing-values-com-pandas/">Manipulando Missing Values com Pandas - Minerando Dados</a></strong></li>
<li><strong><a target="_blank" href="https://jakevdp.github.io/PythonDataScienceHandbook/03.04-missing-values.html">Handling Missing Data - Python Data Science Handbook</a></strong></li>
<li><strong><a target="_blank" href="https://towardsdatascience.com/data-cleaning-with-python-and-pandas-detecting-missing-values-3e9c6ebcf78b">Data Cleaning with Python and Pandas: Detecting Missing Values, por John Sullivan - Towards Data Science</a></strong></li>
<li><strong><a target="_blank" href="https://www.bmc.com/blogs/pandas-nan-missing-data/">Handling Missing Data in Pandas: NaN Values Explained – BMC Software</a></strong></li>
<li><strong><a target="_blank" href="https://sigmoidal.ai/como-tratar-dados-ausentes-com-pandas/">Como Tratar Dados Ausentes com Pandas - Sigmoidal</a></strong></li>
<li><strong><a target="_blank" href="https://towardsdatascience.com/how-to-handle-missing-data-8646b18db0d4">How to Handle Missing Data, por Alvira Swalin - Towards Data Science</a></strong></li>
<li><strong><a target="_blank" href="https://www.mastersindatascience.org/learning/how-to-deal-with-missing-data/">How to Deal with Missing Data - Masters in Data Science</a></strong></li>
<li><strong><a target="_blank" href="https://psycnet.apa.org/record/2012-27075-004">Methods for handling missing data. - PsycNET</a></strong></li>
<li><strong><a target="_blank" href="https://www.kaggle.com/parulpandey/a-guide-to-handling-missing-values-in-python">A Guide to Handling Missing values in Python - Kaggle</a></strong></li>
<li><strong><a target="_blank" href="https://www.flai.com.br/vitordiego/juncao-de-dados-com-pandas-em-python/">Junção de Dados com Pandas em Python – FLAI</a></strong></li>
<li><strong><a target="_blank" href="https://realpython.com/python-data-cleaning-numpy-pandas/">Pythonic Data Cleaning With Pandas and NumPy - Real Python</a></strong></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Aula 8 - Análise e visualização de dados com Python - biblioteca pandas (Parte 4)]]></title><description><![CDATA[Nas aulas anteriores, avançamos na parte mais prática da biblioteca pandas, observando os recursos referentes à importação e manipulação de dados, além de algumas análises iniciais. Desta vez, voltemos o olhar a um aspecto distinto do pandas e do Pyt...]]></description><link>https://blog.matheusyuri.pro/aula-8-analise-e-visualizacao-de-dados-com-python-biblioteca-pandas-parte-4</link><guid isPermaLink="true">https://blog.matheusyuri.pro/aula-8-analise-e-visualizacao-de-dados-com-python-biblioteca-pandas-parte-4</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[data]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Thu, 16 Sep 2021 22:55:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832739442/OapC1AkMA.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Nas aulas anteriores, avançamos na parte mais prática da biblioteca pandas, observando os recursos referentes à importação e manipulação de dados, além de algumas análises iniciais. Desta vez, voltemos o olhar a um aspecto distinto do pandas e do Python que também é muito importante na hora de analisar e, principalmente, apresentar os dados que foram coletados. Essa aula, portanto, é uma introdução básica à visualização de dados em pandas.</p>
<p>O que veremos aqui:</p>
<ul>
<li>Como a visualização de dados é encarada no pandas;</li>
<li>Principais linhas de código para você começar a criar seus próprios gráficos em Python usando o pandas.</li>
</ul>
<h2 id="entao-como-podemos-visualizar-os-dados-com-o-pandas">Então, como podemos visualizar os dados com o pandas?</h2>
<p>A biblioteca pandas baseia sua parte de visualização usando uma API de outra biblioteca, o <strong>Matplotlib</strong>. Por isso mesmo, quando planejamos plotar algum gráfico em um relatório ou <em>notebook</em> usando o pandas, podemos utilizar recursos do Matplotlib para fazer isso.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd <span class="hljs-comment">#Importa o pandas</span>
<span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt <span class="hljs-comment">#Importa a API do Matplotlib</span>
%matplotlib inline <span class="hljs-comment">#Define que os resultados/plots obtidos com o Matplotlib sejam apresentados e armazenados junto do notebook com o qual estamos trabalhando</span>
</code></pre>
<p>A API do Matplotlib, nesse caso, é a <a target="_blank" href="https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.html#module-matplotlib.pyplot"><code>pyplot</code></a>: esta é uma coleção de funções que permitem fazer gráficos simples, mas apresentáveis, e que já ajudam muito na visualização dos dados que importamos e manipulamos com o pandas. Você pode explorar mais as possibilidades de plotagem de gráficos com o pandas que serão apresentadas aqui dando uma olhada no <a target="_blank" href="https://pandas.pydata.org/docs/user_guide/visualization.html#visualization">Guia do Usuário do pandas</a>, além do <a target="_blank" href="https://pandas.pydata.org/docs/user_guide/cookbook.html#cookbook-plotting">Cookbook</a> e o <a target="_blank" href="https://pandas.pydata.org/docs/user_guide/10min.html#plotting">10 minutes to pandas</a>, projetos do próprio site do pandas para compreender melhor a bibiloteca.</p>
<p>Sem mais delongas, vamos à apresentação dos tipos de gráficos que podem ser produzidos usando as bibliotecas pandas e Matpotlib.</p>
<h3 id="o-basico-do-basico-funcao-plot">O básico do básico: função <code>plot()</code></h3>
<p>Essa é a função que servirá de base para fazer as plotagens de gráficos ao usarmos o pandas (e o Matplotlib) em nossos projetos. Por padrão, a função <code>plot()</code> tem como <em>output</em> um gráfico de linhas; é interessante usar esse gráfico ao lidarmos, por exemplo, com <a target="_blank" href="https://docs.tibco.com/pub/spotfire_web_player/6.0.0-november-2013/pt-BR/WebHelp/GUID-60AD831A-D7C3-4407-AA54-44EBD23A29D0.html">conjuntos de dados que possuam amostragens ocorrentes em um período de tempo contínuo</a>.</p>
<p>Para lidarmos com a parte prática da aula, utilizaremos o mesmo conjunto de dados com o qual estamos trabalhando nas últimas semanas (<code>surveys.csv</code>). A partir dele, faremos algumas alterações conforme necessário.  </p>
<pre><code class="lang-python">df = pd.read_csv(<span class="hljs-string">"https://github.com/mhalmenschlager/python-biologia/raw/main/archives/surveys.csv"</span>)
df.head()
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832034913/OEA-VK3Gc.png" alt="image-20210915181223246.png" /></p>
<h4 id="grafico-de-linha">Gráfico de linha</h4>
<p>Como foi já referenciado no título dessa seção, começemos com o básico do básico, usando a função <code>plot()</code> puramente. O retorno será de um <a target="_blank" href="https://pt.wikipedia.org/wiki/Gr%C3%A1fico_de_linha">gráfico de linha</a>, considerando linhas e colunas da tabela que importamos, conforme visto em <code>df.head()</code>:</p>
<pre><code class="lang-pyt">df.plot()
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832088600/3_VAz2rdT.png" alt="image-20210915181449017.png" /></p>
<p>Mesmo que o gráfico não faça o menor sentido nesse momento, já podemos perceber aqui que tipo de resultado teremos quando usarmos a função <code>plot()</code>. Essa função também nos dá possibilidades de plotar gráficos com variáveis específicas, de outros tipos, até mesmo com diferentes títulos e legendas; nesses casos, é necessário apenas adicionar alguns outros argumentos a essa linha, indicando quais variáveis serão consideradas para fazer o gráfico, que tipo de gráfico queremos, e assim por diante. Esses argumentos são colocados dentro dos parênteses da função <code>plot()</code>, conforme o exemplo abaixo:</p>
<pre><code class="lang-python">df.plot(x=<span class="hljs-string">'year'</span>, y=<span class="hljs-string">'record_id'</span>) <span class="hljs-comment">#Especifica os valores dos eixos 'x' e 'y'</span>
</code></pre>
<p>Neste caso, queremos especificar que tipos de variáveis queremos que apareçam nos eixos <code>x</code> e <code>y</code>; usemos as variáveis de ano e ID de registro como exemplo. O resultado dessa linha de código possui um pouco mais de sentido pois, a partir do gráfico, podemos avaliar a evolução das quantidades de amostragem conforme os anos considerados no <em>dataframe</em>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832122191/lV0a4jmP0.png" alt="image-20210915183741265.png" /></p>
<p>Outro exemplo que podemos utilizar para explorar o gráfico de linhas, e que também envolve os anos de amostragem, tem a ver com agrupamentos. Nessa situação, veremos a contagem total de amostras feitas por cada ano, e a partir disso plotar um gráfico para acompanhar visualmente a evolução dessa amostragem. Para tanto, utilizaremos as funções <code>groupby</code>e <code>count</code> na mesma linha de código antes de plotarmos o gráfico, para organização do <em>frame</em> que será a base do gráfico.</p>
<pre><code class="lang-python">year = df.groupby(<span class="hljs-string">'year'</span>)[<span class="hljs-string">'record_id'</span>].count() <span class="hljs-comment">#Contagem de amostragens, com base em seus IDs, por ano</span>
year.head() <span class="hljs-comment">#Cinco primeiras entradas do frame</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832161805/5AnsTTH0E.png" alt="image-20210915200426972.png" /></p>
<p>A partir disso, usaremos o objeto criado <code>year</code> para plotar um gráfico de linha:</p>
<pre><code class="lang-python">year.plot() <span class="hljs-comment">#Gráfico de linha do objeto 'year'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832192460/hrL0UKDeT.png" alt="image-20210915200811721.png" /></p>
<blockquote>
<p><strong>Uma dica</strong>: Por n+1 razões, haverá momentos em que a figura parecerá pequena para a quantidade de informação que está dentro dela. Quando ocorrer isso, podemos sempre lançar mão do argumento <code>figsize</code> para ajustar o tamanho da figura até que ela fique em um tamanho que se possa considerar razoável.</p>
</blockquote>
<pre><code class="lang-python">year.plot(figsize=(<span class="hljs-number">17</span>,<span class="hljs-number">3</span>)) <span class="hljs-comment">#Gráfico de linha do objeto 'year', com tamanho de figura (17,3)</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832225384/U6m8XzK-f.png" alt="image-20210915200935736.png" /></p>
<h3 id="avancando-na-funcao-plot-outros-tipos-de-graficos-disponiveis">Avançando na função <code>plot()</code>: outros tipos de gráficos disponíveis</h3>
<p>Como dito anteriormente, a função <code>plot()</code>, além dos gráficos de linha, possibilita ao usuário plotar uma série de gráficos. A documentação do pandas expõe, em detalhes, as capacidades de visualização de dados do pandas; aqui, serão expostos alguns baseados no <em>dataframe</em> que estamos utilizando como exemplo. </p>
<h4 id="grafico-de-barras">Gráfico de barras</h4>
<p>Enquanto um gráfico de linhas é mais utilizado para acompanhar a evolução de uma amostragem usando uma série contínua, geralmente temporal, o <a target="_blank" href="https://pt.wikipedia.org/wiki/Gr%C3%A1fico_de_barras">gráfico de barras</a> é largamente recomendado para <a target="_blank" href="https://docs.tibco.com/pub/spotfire_web_player/6.0.0-november-2013/pt-BR/WebHelp/GUID-6023CECC-E502-4AE1-B5C5-FFE5DAF6FAE2.html">avaliar as amostragens de um conjunto de dados categóricos</a>. Usando o <code>df</code> ainda como exemplo, em vez de avaliarmos as amostragens de acordo com os anos de coleta, podemos observar a quantidade de coletas feitas de acordo com as espécies consideradas. Em vez de utilizarmos a variável <code>year</code>, dessa vez nos valeremos da variável <code>species_id</code>, e a partir da quantidade de IDs feitos, poderemos observar as diferenças entre espécies.</p>
<pre><code class="lang-python">count = df.groupby(<span class="hljs-string">'species_id'</span>)[<span class="hljs-string">'record_id'</span>].count() <span class="hljs-comment">#Contagem dos IDs das amostragens de acordo com os IDs de espécies</span>
count.head() <span class="hljs-comment">#As cinco primeiras entradas do objeto 'count'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832259023/1kjG8Q2Dm.png" alt="image-20210916110116609.png" /></p>
<pre><code class="lang-python">count.plot(kind=<span class="hljs-string">'bar'</span>, figsize=(<span class="hljs-number">18</span>,<span class="hljs-number">3</span>)) <span class="hljs-comment">#Plotagem de um gráfico de barras do objeto 'count', com tamanho (18, 3)</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832295691/1UYgeS-uv.png" alt="image-20210916110245761.png" /></p>
<p>O resultado do plot é a amostragem de espécies em ordem alfabética. Aqui, já vemos a representatividade de algumas espécies, como 'DM', 'DO', 'OT', e 'PP' no número total de coletas. Se quisermos organizar os dados de forma ordenada, do maior para o menor, por exemplo, antes de usarmos a função <code>plot()</code> é preciso apenas usar a função <code>sorting.values()</code>. Assim, criaremos um novo objeto, <code>count2</code>, adicionando esse argumento.</p>
<pre><code class="lang-python">count2 = df.groupby(<span class="hljs-string">'species_id'</span>)[<span class="hljs-string">'record_id'</span>].count().sort_values(ascending = <span class="hljs-literal">False</span>) <span class="hljs-comment">#Contagem dos IDs das amostragens de acordo com os IDs de espécies, de forma ordenada. O (ascending = False) indica que a organização será feita de forma decrescente, do maior para o menor.</span>
count2.head() <span class="hljs-comment">#As cinco primeiras entradas do objeto 'count2'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832338344/IPusGykUp.png" alt="image-20210916123737876.png" /></p>
<pre><code class="lang-python">count2.plot(kind=<span class="hljs-string">'bar'</span>, figsize=(<span class="hljs-number">18</span>,<span class="hljs-number">3</span>)); <span class="hljs-comment">#Plotagem de um gráfico de barras do objeto 'count2', com tamanho (18, 3)</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832372209/_hQLuW2Yj.png" alt="image-20210916144219939.png" /></p>
<p>Aqui já vemos um gráfico mais bem organizado, com uma ordenação decrescente da amostragem das espécies. Lembre-se que cada ID de espécies é associado com o nome desta; você pode ver isso com mais detalhes nas aulas anteriores, com o dicionário de variáveis, bem como no repositório da série no GitHub.</p>
<h4 id="grafico-de-pizza">Gráfico de pizza</h4>
<p>O <a target="_blank" href="https://docs.tibco.com/pub/spotfire_web_player/6.0.0-november-2013/pt-BR/WebHelp/GUID-8B1036A5-6BE9-4A84-B532-8E15060CABA9.html">gráfico de pizza</a> é, sem dúvidas, um dos mais utilizados por qualquer profissional, independente da área. E, infelizmente, <a target="_blank" href="https://towardsdatascience.com/pie-charts-considered-harmful-36268a4e42e6">é um dos gráficos mais mal utilizados</a>; embora a proposta seja a exibição de dados de uma forma fácil de ler, <a target="_blank" href="https://www.businessinsider.com/pie-charts-are-the-worst-2013-6">muitas vezes os resultados são horrendos</a> (em uma outra postagem envolvendo visualização de dados, escreverei mais sobre). </p>
<p>Esse gráfico é muito usado para apresentar proporções entre os dados amostrados, mais frequentemente na forma de porcentagens. Plotá-lo com o pandas também é muito simples, ainda usando a função <code>plot()</code>. Comecemos separando os dados que utilizaremos aqui: observaremos a contagem total de três espécies, <code>'DM'</code>, <code>'DO'</code>, e <code>PP</code>, utilizando a função <code>count()</code>, e separando-as por um <code>groupby()</code>.</p>
<pre><code class="lang-python">dmXdoXpp = df.groupby(<span class="hljs-string">'species_id'</span>)[<span class="hljs-string">'record_id'</span>].count()[[<span class="hljs-string">'DO'</span>, <span class="hljs-string">'DM'</span>, <span class="hljs-string">'PP'</span>]] <span class="hljs-comment">#Contagem da amostragem das espécies 'DM', 'DO', e 'PP', considerando seus IDs de registro</span>
dmXdoXpp <span class="hljs-comment">#Chamamento do objeto 'dmXdoXpp'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832412900/Lkn40W14D.png" alt="image-20210916145641879.png" /></p>
<pre><code class="lang-python">dmXdoXpp.plot(kind=<span class="hljs-string">'pie'</span>) <span class="hljs-comment">#Plotagem de um gráfico de pizza do objeto 'dmXdoXpp'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832441813/0ahQu53xY.png" alt="image-20210916182302293.png" /></p>
<h4 id="grafico-de-caixa-boxplot">Gráfico de caixa (<em>boxplot</em>)</h4>
<p>Gráficos de caixa, ou <a target="_blank" href="https://pt.wikipedia.org/wiki/Diagrama_de_caixa"><em>boxplots</em></a>, são largamente utilizados para avaliar a variação de um conjunto de dados através de um <a target="_blank" href="https://operdata.com.br/blog/como-interpretar-um-boxplot/">sistema de máximos, mínimos, e quartis ou percentis</a>. São ótimos para ver como se comportam as amostragens de um determinado grupo ou variável, propiciando inclusive a verificação de dados que são muito discrepantes, os chamados <em>outliers</em>. Esse tipo de plotagem é muito conhecido por estar presente em <a target="_blank" href="https://pt.wikipedia.org/wiki/An%C3%A1lise_explorat%C3%B3ria_de_dados">Análises Exploratórias de Dados (AEDs)</a>, que são as primeiras análises a serem feitas após a coleta de dados. No caso do <em>boxplot</em>, destacamos aqui uma função levemente distinta do simples <code>plot()</code>para fazê-lo, embora seja possível ir por esse caminho também.</p>
<p>Para mostrar como se faz um <em>boxplot</em> com o pandas, criaremos um novo objeto, <code>MxF</code>, uma vez que avaliaremos a variação do comprimento do retropé conforme o sexo de cada animal amostrado. Para isso, faremos uma nova tabela, com a função <a target="_blank" href="https://www.vooo.pro/insights/pivot-table-em-pandas-explicado/"><code>pivot_table()</code></a>:</p>
<pre><code class="lang-python">MxF = df.pivot_table(<span class="hljs-string">'hindfoot_length'</span>, <span class="hljs-string">'record_id'</span>, <span class="hljs-string">'sex'</span>) <span class="hljs-comment">#Tabela com a variação do comprimento do retropé de acordo com o sexo das amostras consideradas no conjunto de dados</span>
MxF
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832482426/yhZLm1MfnP.png" alt="image-20210916183825589.png" /></p>
<p>Para fazer a plotagem do gráfico de caixas, usaremos aqui a função <code>boxplot()</code> a partir do novo objeto:</p>
<pre><code class="lang-python">MxF.boxplot(); <span class="hljs-comment">#Gráfico de caixa do objeto 'MxF'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832508522/N0Psfwbpt.png" alt="image-20210916184010123.png" /></p>
<p>Neste gráfico, já podemos ter uma ideia da variação do comprimento em centímetros do retropé de cada amostragem considerada, com a separação por sexo. Repare que, quando chamada a função <code>boxplot()</code>, o gráfico aparece com um gradeamento. Há uma linha de código alternativa para criar um gráfico de caixas que usa a função <code>plot()</code>, só que essa sem gradeamento:</p>
<pre><code class="lang-python">MxF.plot(kind = <span class="hljs-string">'box'</span>) <span class="hljs-comment">#Gráfico de caixa do objeto 'MxF'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631832543331/GTyyKKETX.png" alt="image-20210916184320434.png" /></p>
<h4 id="outros-tipos-de-grafico-suportados-pelo-pandas">Outros tipos de gráfico suportados pelo pandas</h4>
<p>Além desses, há outros tipos de gráfico (área, <em>scatter plot</em>, etc.) que são suportados pela biblioteca pandas, que não são mencionados aqui; isso permite que o usuário possa fazer gráficos apresentáveis para seus relatórios, apresentações ou outras exposições usando uma só biblioteca. Para conhecer e praticar mais exaustivamente, é recomendada uma leitura atenta à documentação do pandas, onde se expõe, com exemplos práticos, todas as possibilidades que a biblioteca oferece para visualização de dados.</p>
<p>Outras bibliotecas, como o Matplotlib e o Seaborn, fazem parte do ecossistema do pandas e são especializados em visualização de dados. Em outro momento da série, esses recursos serão apresentados com mais detalhes, e haverá uma discussão mais extensa sobre a visualização de dados em Python, e como você pode utilizar essas ferramentas da melhor forma possível com seus dados.</p>
<hr />
<p>Por aqui, encerramos uma outra aula de apresentação da biblioteca pandas. Com o que já foi exposto aqui, você já tem conhecimento e referências para começar a fazer suas próprias análises de dados. Não esqueça de fazer duas coisas importantes: ler de forma exaustiva as documentações e referências expostas nas aulas, e praticar muito, com o <em>dataset</em> de exemplo e tantos outros. Com isso, você aprenderá a usar a linguagem Python para alçar posições de destaque na sua área profissional e/ou acadêmica, seja na Ecologia, em outras áreas da Biologia, ou com outros projetos de seu interesse. Aproveite para deixar um feedback das aulas e, caso surjam dúvidas ou curiosidades acerca dos temas expostos por aqui, estarei sempre à disposição para auxílio ou, até mesmo, uma motivação a mais. Siga buscando conhecimento!</p>
<p>Um grande abraço, até a próxima aula e, sobretudo, divirta-se com os gráficos!</p>
<hr />
<p><strong>Para ler mais</strong></p>
<ul>
<li><a target="_blank" href="https://www.analyticsvidhya.com/blog/2021/02/an-intuitive-guide-to-visualization-in-python/"><strong>Data Visualization in Python | Data Visualization for Beginners</strong></a></li>
<li><a target="_blank" href="https://mode.com/blog/python-data-visualization-libraries/"><strong>10 Python Data Visualization Libraries for Any Field - Mode.com</strong></a></li>
<li><a target="_blank" href="https://pandas.pydata.org/docs/getting_started/intro_tutorials/04_plotting.html"><strong>How to create plots in pandas? — Documentação do pandas</strong></a></li>
<li><a target="_blank" href="https://realpython.com/pandas-plot-python/"><strong>Plot With Pandas: Python Data Visualization for Beginners – Real Python</strong></a></li>
<li><a target="_blank" href="https://datatofish.com/plot-dataframe-pandas/"><strong>How to Plot a DataFrame using Pandas - Data to Fish</strong></a></li>
<li><a target="_blank" href="https://www.w3schools.com/python/pandas/pandas_plotting.asp"><strong>Pandas - Plotting - w3schools</strong></a></li>
<li><a target="_blank" href="https://digitalinnovation.one/artigos/pandas-visualizacao-inicial-dos-dados"><strong>Pandas - Visualização inicial dos dados - Digital Innovation One</strong></a></li>
<li><a target="_blank" href="https://www.kaggle.com/joaoavf/introducao-a-analise-de-dados-python-e-pandas"><strong>Introdução à Análise de Dados - Python e pandas - Kaggle</strong></a></li>
<li><a target="_blank" href="https://ichi.pro/pt/uma-folha-de-dicas-definitiva-para-visualizacao-de-dados-em-pandas-272387423377719"><strong>Uma folha de dicas definitiva para visualização de dados em pandas - Ichi.pro</strong></a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Aula 7 - Análise e visualização de dados em Python - Biblioteca pandas (parte 3)]]></title><description><![CDATA[Nas últimas aulas, foram abordadas vários recursos do pandas que você pode utilizar em suas práticas com dados, abordando também conceitos essenciais para você aproveitar essa biblioteca do Python da melhor maneira. Nessa aula, continuaremos nessa me...]]></description><link>https://blog.matheusyuri.pro/aula-7-analise-e-visualizacao-de-dados-em-python-biblioteca-pandas-parte-3</link><guid isPermaLink="true">https://blog.matheusyuri.pro/aula-7-analise-e-visualizacao-de-dados-em-python-biblioteca-pandas-parte-3</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[data]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Wed, 01 Sep 2021 14:28:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1630506466037/rI0wCo8Jj.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Nas últimas aulas, foram abordadas vários recursos do pandas que você pode utilizar em suas práticas com dados, abordando também conceitos essenciais para você aproveitar essa biblioteca do Python da melhor maneira. Nessa aula, continuaremos nessa mesma pegada.</p>
<p>Nessa aula, veremos:</p>
<ul>
<li>Outros métodos de fatiamento: <code>loc</code> e <code>iloc</code>;</li>
<li>Seleções por critérios</li>
</ul>
<h2 id="outros-metodos-de-fatiamento-loc-e-iloc">Outros métodos de fatiamento: <code>loc</code> e <code>iloc</code></h2>
<p>Anteriormente, vimos já alguns métodos do processo chamado de <em>fatiamento</em> ou <em>slicing</em>, no qual é possível criar novos frames separando linhas e colunas com as quais se quer trabalhar. No pandas, existem uma série de recursos que exploram esse processo, tornando a experiência com a biblioteca mais proveitosa à medida em que vai se dominando as diferentes maneiras de seleção de linhas e colunas. Nessa aula, serão apresentados os métodos <code>loc</code>e <code>iloc</code>.</p>
<h3 id="metodo-loc-localizacao-por-rotulos">Método <code>loc</code> - Localização por rótulos</h3>
<p><em>Grosso modo</em>, o método de seleção <code>loc</code> seleciona linhas e colunas de acordo com o seu rótulo (<em>label</em>), isto é, seu "nome" na tabela, aquilo que aparece visualmente quando temos um <em>output</em> de comando. Você pode usar essa seleção de acordo com algumas fórmulas:</p>
<ul>
<li><code>df.loc[linha]</code> : Seleciona uma ou mais linhas pelo seu rótulo;</li>
<li><code>df.loc[: , coluna]</code>: Seleciona uma ou mais colunas pelo seu rótulo;</li>
<li><code>df.loc[linha, coluna]</code>: Seleciona linhas e colunas pelo seu rótulo.</li>
</ul>
<p>Vejamos isso em termos práticos, usando o <em>dataframe</em> <code>df</code>, já nosso conhecido:</p>
<pre><code class="lang-python">df.loc[<span class="hljs-string">'NL'</span>] <span class="hljs-comment">#Seleciona as linhas contendo a ID de espécie 'NL'</span>

df.loc[<span class="hljs-string">'NL'</span>, [<span class="hljs-string">'sex'</span>, <span class="hljs-string">'hindfoot_length'</span>]] <span class="hljs-comment">#Seleciona as linhas nas colunas 'sex' e 'hindfoot_length' contendo a ID de espécie 'NL'</span>

df.loc[:[<span class="hljs-string">'year'</span>,<span class="hljs-string">'species_id'</span>]] <span class="hljs-comment">#Seleciona as colunas 'year' e 'species_id'</span>

df.loc[[<span class="hljs-string">'NL'</span>, <span class="hljs-string">'DM'</span>, <span class="hljs-string">'DO'</span>], [<span class="hljs-string">'sex'</span>, <span class="hljs-string">'hindfoot_length'</span>]] <span class="hljs-comment">#Seleciona as linhas nas colunas 'sex' e 'hindfoot_length' contendo a IDs de espécie 'NL', 'DM' e 'DO'</span>
</code></pre>
<p>Acima, portanto, fomos selecionando diversas linhas e colunas observando sempre seus rótulos na tabela. Quando da seleção apenas de colunas, repare o uso do <code>:</code> isolado; este indica que serão filtradas todas as linhas do <em>dataframe</em>.  A separação de linhas e colunas no comando, repare também, é feita pelo separador <code>,</code>. Um outro detalhe importante de se destacar: ao usar os métodos de seleção, atente a utilizar sempre linhas e colunas não-nulas (apontados comumente como <code>NaN</code>; veremos o que são dados nulos -  e o que fazer com eles - com mais detalhes em outra aula).</p>
<blockquote>
<p><strong>Que tal fazer você mesmo?</strong></p>
<p>Com o primeiro notebook da serie e os dados e a biblioteca pandas importadas nele, experimente fazer uma seleção com espécies e colunas diferentes, sempre usando o <code>df.loc</code>. <em>Pratique bastante, e encorajo-lhe a buscar outras referências e exemplos na literatura ou na Internet para entender melhor. Algumas sugestões de lugares para buscar mais ajuda estarão em "Para ler mais"</em></p>
</blockquote>
<h3 id="metodo-iloc-localizacao-por-numeros-inteiros">Método <code>iloc</code> - Localização por números inteiros</h3>
<p>O método <code>iloc</code> segue o mesmo princípio do <code>loc</code>, mas com uma diferença essencial: enquanto o <code>loc</code> faz uma seleção por rótulos, o <code>iloc</code> busca linhas e colunas em relação às suas localizações inteiras (em números). Cada linha e coluna em um <em>dataframe</em> possui uma localização inteira que a define, sendo isso uma espécie de acréscimo ao rótulo que é exibido no <em>output</em> de cada comando. Essa localização é o número da linha/coluna no qual o nosso alvo estará localizado, sempre começando da parte superior esquerda.</p>
<p>Para usar esse método, podemos nos basear nas seguintes fórmulas:</p>
<ul>
<li><code>df.iloc[0]</code>: Seleciona a primeira linha por sua localização inteira;</li>
<li><code>df.iloc[linha]</code>: Seleciona uma linha por sua localização inteira;</li>
<li><code>df.iloc[:, coluna]</code>: Seleciona uma coluna por sua localização inteira;</li>
</ul>
<p>Vejamos isso em termos práticos, usando outra vez o <em>dataframe</em> <code>df</code>:</p>
<pre><code class="lang-python">df.iloc[<span class="hljs-number">0</span>] <span class="hljs-comment">#Seleciona a primeira linha de 'df'</span>

df.iloc[<span class="hljs-number">4</span>] <span class="hljs-comment">#Seleciona a quinta linha de 'df' (lembre-se: a contagem de linhas no Python começa por 0)</span>

df.iloc[:, <span class="hljs-number">2</span>] <span class="hljs-comment">#Seleciona a terceira coluna de 'df'</span>

df.iloc[[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>], [<span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>]] <span class="hljs-comment">#Seleciona a segunda e terceira linha, e a primeira, terceira, e segunda coluna de 'df', nesta ordem</span>
</code></pre>
<blockquote>
<p><strong>Que tal fazer você mesmo?</strong></p>
<p>Com os dados de <code>df</code>em mãos, aproveite para testar o método <code>iloc</code>, localizando diferentes linhas e colunas na tabela. Se você não se lembra a quantidade de linhas e colunas que há no <em>dataframe</em>, é simples descobrir: use o comando <code>df.shape()</code>. É esperado que o <em>output</em> venha na fórmula <code>(linhas, colunas)</code>. <em>Pratique bastante, e encorajo-lhe a buscar outras referências e exemplos na literatura ou na Internet para entender melhor. Algumas sugestões de lugares para buscar mais ajuda estarão em "Para ler mais"</em></p>
</blockquote>
<h2 id="selecoes-por-criterios">Seleções por critérios</h2>
<p>No pandas, além de fazermos seleções por posição ou rótulo, também podemos selecionar informações de nossos <em>dataframes</em> por uma série de critérios ou condições expressos nas linhas de comando.</p>
<h3 id="entendi-foi-nada-o-que-seriam-esses-criterios-ou-condicoes">Entendi foi nada: o que seriam esses 'critérios' ou 'condições'?</h3>
<p>Como temos conhecimento de como estão dispostos os dados no <em>dataframe</em> que estamos utilizando aqui, podemos fazer <em>subsets</em> (um <em>dataframe</em> do <em>dataframe</em>) baseados em normas ou critérios que podemos estabelecer. Se você quiser, por exemplo, separar todas as linhas de amostras que foram coletadas no ano de 2001, apenas é preciso usar um operador lógico do Python para chegar a esse fim, o <code>==</code>. Veja um exemplo:</p>
<pre><code class="lang-python">df_2001 = df[df.year == <span class="hljs-number">2001</span>] <span class="hljs-comment">#Separa as linhas cujo ano, 'year', é igual a 2001</span>
</code></pre>
<p>Nesse caso, estamos criando um novo <em>dataframe</em>, <code>df_2001</code>, usando o nosso <em>frame</em> principal, <code>df</code>, com a condição/critério de que sejam selecionados apenas as linhas que, na coluna <code>year</code>, possuam  o valor de ano <code>2001</code>. Assim, se chamarmos <code>df_2001</code>, aparecerá o <em>dataframe</em> criado com a condição que fora estabelecida. </p>
<p>Não apenas para selecionar valores que coincidam com o critério, podemos usar outros operadores lógicos do Python para criar novos <em>dataframes</em>. Tais operadores são, segundo a sintaxe:</p>
<ul>
<li><code>==</code>: igual a;</li>
<li><code>!=</code>: não igual a;</li>
<li><code>&gt;</code> ou <code>&lt;</code>: maior ou menor que;</li>
<li><code>&gt;=</code>: maior ou igual que;</li>
<li><code>&lt;=</code>: menor ou igual que.</li>
</ul>
<p>Se, por algum acaso, queiramos definir mais de um conjunto de critérios, podemos utilizar o operador <code>&amp;</code> para conectá-los:</p>
<pre><code class="lang-python">df_conj = df[(df.year &gt;= <span class="hljs-number">1990</span>) &amp; (df.year &lt;= <span class="hljs-number">1995</span>)] <span class="hljs-comment">#Separa as linhas cujas amostragens possuam valor 'year' maior ou igual a 1990, e menor ou igual a 1995</span>
</code></pre>
<blockquote>
<p><strong>Que tal fazer você mesmo?</strong></p>
<p>Da mesma forma que usamos o <code>df</code> para explorar as possibilidades de usar os métodos <code>loc</code> e <code>iloc</code>, podemos aqui utilizar esse <em>dataframe</em> para fitrá-lo de acordo com condições que nós mesmos podemos estabelecer. Assim sendo, você pode explorar os operadores lógicos do Python para escrever algumas linhas de código.</p>
</blockquote>
<hr />
<p>Nessa aula vimos mais alguns recursos do pandas para fazer seleções de linhas e colunas, além da criação de <em>subsets</em>. Esses são aspectos essenciais a se levar em conta ao trabalhar com dados, uma vez que eles proporcionam uma variedade de possibilidades de se manipular tabelas sem a necessidade de carregar o mesmo <em>dataset</em> toda vez; isso facilita, e muito, o trabalho a ser feito. Nas próximas aulas continuaremos a discutir sobre como manipular dados com o pandas; mas antes, será interessante apresentar para vocês algumas características dessa biblioteca no que se refere à visualização de dados. Haverá, portanto, uma apresentação de códigos e conceitos para plotar dados usando pandas. Com isso, você já pode avançar nos primeiros relatórios usando seu próprio material, tendo já visto o resumo estatístico e um pouco de manipulação de tabelas.</p>
<p>Recomendo fortemente, mais uma vez, que você dê uma olhada nas referências apresentadas no 'Para ler mais'. Ali estarão links de várias fontes com as quais você poderá explorar os processos de seleção do pandas de forma exaustiva, com um conteúdo bastante didático.</p>
<p>Dito isso, vejo vocês na próxima aula. Um grande abraço!</p>
<hr />
<p><strong>Para ler mais:</strong></p>
<ul>
<li><strong><a target="_blank" href="https://towardsdatascience.com/23-efficient-ways-of-subsetting-a-pandas-dataframe-6264b8000a77">23 Efficient Ways of Subsetting a pandas DataFrame - Towards Data Science</a></strong></li>
<li><strong><a target="_blank" href="https://www.geeksforgeeks.org/selecting-rows-in-pandas-dataframe-based-on-conditions/">Selecting rows in pandas DataFrame based on conditions - GeeksforGeeks</a></strong></li>
<li><strong><a target="_blank" href="https://panda.ime.usp.br/pensepy/static/pensepy/06-Selecao/selecao.html">Decisões e Seleção — Como pensar como um Cientista da Computação: Edição Interativa em Python</a></strong></li>
<li><strong><a target="_blank" href="https://www.dunderdata.com/master-data-analysis-with-python">A comprehensive guide to mastering data analysis with pandas - Dunder Data</a></strong></li>
<li><strong><a target="_blank" href="https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html">Indexing and selecting data — pandas 1.3.2 documentation</a></strong></li>
<li><strong><a target="_blank" href="https://qastack.com.br/programming/509211/understanding-slice-notation">Noções básicas sobre notação de fatia - QAStack</a></strong></li>
<li><strong><a target="_blank" href="https://qastack.com.br/programming/11285613/selecting-multiple-columns-in-a-pandas-dataframe">Selecionando várias colunas em um dataframe do pandas - QAStack</a></strong></li>
<li><strong><a target="_blank" href="https://towardsdatascience.com/5-essential-pandas-tips-for-easier-data-manipulation-4c2968d37a79">5 Essential Pandas Tips For Easier Data Manipulation - Towards Data Science</a></strong></li>
<li><strong><a target="_blank" href="https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.loc.html?highlight=loc#pandas.DataFrame.loc">pandas.DataFrame.loc — pandas 1.3.2 documentation</a></strong></li>
<li><strong><a target="_blank" href="https://qastack.com.br/programming/31593201/how-are-iloc-ix-and-loc-different">Qual a diferença entre iloc, ix e loc? - QAStack</a></strong></li>
<li><strong><a target="_blank" href="https://www.delftstack.com/pt/howto/python-pandas/pandas-loc-vs-iloc-python/">Pandas loc vs iloc | Delft Stack</a></strong></li>
<li><strong><a target="_blank" href="https://towardsdatascience.com/loc-vs-iloc-in-pandas-92fc125ed8eb">loc vs iloc in Pandas and Python - Towards Data Science</a></strong></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Aula 6 - Análise e visualização de dados em Python - Biblioteca pandas (Parte 2)]]></title><description><![CDATA[A parte prática da série segue nessa nova aula, ainda com o pandas; avançaremos um pouco mais na biblioteca, vendo seu poder e possibilidades de análise de dados.
O que veremos nessa aula:

Um pouco mais sobre agrupamento: value_counts(), unique()e c...]]></description><link>https://blog.matheusyuri.pro/aula-6-analise-e-visualizacao-de-dados-em-python-biblioteca-pandas-parte-2</link><guid isPermaLink="true">https://blog.matheusyuri.pro/aula-6-analise-e-visualizacao-de-dados-em-python-biblioteca-pandas-parte-2</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[data]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Wed, 25 Aug 2021 14:00:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1629899871877/PCK6psA27.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A parte prática da série segue nessa nova aula, ainda com o pandas; avançaremos um pouco mais na biblioteca, vendo seu poder e possibilidades de análise de dados.</p>
<p>O que veremos nessa aula:</p>
<ul>
<li>Um pouco mais sobre agrupamento: <code>value_counts()</code>, <code>unique()</code>e <code>count()</code>;</li>
<li>Referenciando e copiando objetos no pandas.</li>
</ul>
<h2 id="um-pouco-mais-sobre-agrupamento">Um pouco mais sobre agrupamento</h2>
<p>Aqui, vamos explorar mais um pouco as possibilidades que se tem ao usar o pandas para fazer agrupamentos e fatiamentos. Esses conceitos já foram explicados na aula passada; caso não lembre, é só voltar um post e verificar o texto e as referências sobre essa parte.</p>
<p>Anteriormente, nós vimos uma função chamada <code>value_counts()</code>, para ver quantos registros de cada sexo temos no <em>dataset</em> que estamos utilizando. Há um outro recurso usando essa função que é interessante, envolvendo a proporção de cada variável numa determinada coluna. Para ver o resultado disso, apenas é necessário adicionar um outro argumento dentro de <code>value_counts()</code>, envolvendo um processo de normalização dos dados. A linha de código fica assim:</p>
<pre><code class="lang-python">df[[<span class="hljs-string">'sex'</span>]].value_counts(normalize = <span class="hljs-literal">True</span>)
</code></pre>
<blockquote>
<p><strong>Que tal fazer você mesmo?</strong></p>
<p>Nessa parte envolvendo a função <code>value_counts()</code>, vimos o recurso de proporção, que usa o recurso da normalização, que é bastante interessante. Com esse mesmo recurso, podemos também extrair a representatividade de cada variável em porcentagem. Como você poderia fazer isso?</p>
</blockquote>
<h3 id="funcoes-unique-e-count">Funções <code>unique()</code> e <code>count()</code></h3>
<p>Uma função parecida com o <code>value_counts()</code>, que já vimos antes, é a função <code>count()</code>. A diferença entre elas é que a segunda, em termos básicos, permite avaliar uma contagem de uma variável por outra, usando o <code>groupby</code> em vez de usar apenas uma variável para contar.</p>
<p>Para entender melhor: fizemos na aula anterior um agrupamento por sexo (variável <code>sex</code>), avaliando quantas ocorrências de cada sexo há no <em>dataframe</em> que estamos utilizando. Agora, trabalharemos um pouco com as identificações de espécies do conjunto de dados. Para descobrir quais são as espécies registradas, podemos lançar mão da função <code>unique()</code>:</p>
<pre><code class="lang-python">df[<span class="hljs-string">'species_id'</span>].unique() <span class="hljs-comment">#Quais são as espécies que aparecem no dataframe</span>
</code></pre>
<p>A partir disso, se queremos observar quantos registros existe para cada espécie, lançamos mão da função <code>count()</code></p>
<pre><code class="lang-python">df.groupby(<span class="hljs-string">'species_id'</span>)[<span class="hljs-string">'record_id'</span>].count() <span class="hljs-comment">#Número de amostras por cada espécie</span>
</code></pre>
<p>Ainda, se queremos saber a amostragem de uma espécie apenas, podemos adicionar mais um argumento à linha de código. Neste caso, ao final da linha, escrevemos o nome da espécie em colchetes (<code>['SP']</code>):</p>
<pre><code class="lang-python">df.groupby(<span class="hljs-string">'species_id'</span>)[<span class="hljs-string">'record_id'</span>].count()[<span class="hljs-string">'DO'</span>]
</code></pre>
<blockquote>
<p><strong>Que tal fazer você mesmo?</strong></p>
<p>Aproveite a linha de código acima para obter resultados de espécies diferentes!</p>
</blockquote>
<h2 id="a-diferenca-entre-associarreferenciar-e-copiar-objetos">A diferença entre associar/referenciar e copiar objetos</h2>
<h3 id="copiando-objetos">Copiando objetos</h3>
<p>Em aulas passadas, vimos como é possível criar objetos em um ambiente Jupyter com o Python, e a importância dessa criação para analisar dados. Às vezes, por certa precaução, nos é recomendado não trabalhar em cima de apenas um objeto de dado <em>dataframe</em> no Python; isso porque corremos o risco de perder informações ao chamar alguma função sem querer. Então, para garantirmos que ficará tudo bem, podemos criar novos objetos a partir de um mesmo <em>dataframe</em> com o mesmo conteúdo; isso seria uma <strong>cópia</strong> do objeto. Obtemos essas cópias de objetos usando o método <code>copy()</code>.</p>
<pre><code class="lang-python">df_copia = df.copy()
</code></pre>
<p>Com essa linha de código, portanto, criamos um novo objeto, chamado <code>df_copia</code>; tal objeto possui um novo <em>dataframe</em>, que tem conteúdo igual ao objeto <code>df</code>, sendo possível assim usá-lo para diferentes propósitos.</p>
<blockquote>
<p><strong>Que tal fazer você mesmo?</strong>: Repita essa operação em um notebook Jupyter/do Google Colab, com a mesma fonte de dados que estamos utilizando, criando o objeto <code>df_copia</code>, e compare os objetos. Você pode fazer isso usando a função <code>head()</code>.</p>
</blockquote>
<h3 id="referenciando-objetos">Referenciando objetos</h3>
<p>Suponhamos que alguém alegue que achou uma solução "mais simples e mais rápida" para essa situação. Observe a linha abaixo:</p>
<pre><code class="lang-pytho">df_copia = df
</code></pre>
<p>Com ela, argumenta esse alguém, criamos o mesmo objeto, <code>df_copia</code>, usando o <code>df</code> que utilizamos como <em>dataframe</em> anteriormente; isso teria o mesmo efeito que usar a função <code>copy()</code>, ao fazermos o mesmo exercício de comparação anterior. Logo, em vez de usarmos o <code>copy()</code> para fazer uma nova cópia de <code>df</code>, apenas criamos um novo objeto usando esse mesmo <em>dataframe</em>, porque dá na mesma... certo?</p>
<p>Nada mais errado. E eu explico o porquê:</p>
<p>O que se está a fazer aqui é, basicamente, dar um outro nome de objeto a um mesmo <em>dataframe</em>. Esse é o processo, em Python, chamado de <strong>associação</strong> ou <strong>referência</strong>. Então, nesse caso, <code>df</code> pode ser chamado tanto por esse nome, quanto pelo nome <code>df_copia</code>. </p>
<p>Para entender melhor, usando a mesma fonte: Imagine que estamos criando agora três objetos distintos, a saber:</p>
<pre><code class="lang-python">df2 = df.copy()
df3 = df
</code></pre>
<p>Observe que, enquanto o <code>df2</code> é criado usando a função <code>copy()</code>, o <code>df3</code> é criado fazendo uma referência à <code>df</code>. Em princípio, os dois objetos estariam associados com o mesmo <em>dataframe</em>, se seguirmos a ideia anterior. Ao verificarmos os dois nomes usando a função <code>head()</code>ou <code>info()</code>, percebemos que eles são iguais, certo? </p>
<p>Até aqui, o pensamento está OK, mas façamos uma coisa diferente nessa situação. Usemos o <code>df2</code> para fazer uma inclusão de colunas nele (isso será visto em uma próxima aula com mais detalhes, não se preocupe; a ideia agora é apenas fazer uma mudança):</p>
<pre><code class="lang-python">df2[<span class="hljs-string">'alternative_id'</span>] = <span class="hljs-number">0.0</span> <span class="hljs-comment">#Incluir uma coluna no 'df2'</span>
</code></pre>
<p>Feita essa mudança, verifiquemos de novo , usando a função <code>head()</code> ou <code>info()</code>. Se você fizer isso no Google Colab ou em um Jupyter Notebook, perceberá que <code>df2</code> e <code>df3</code>, em seu conteúdo, são agora diferentes um do outro. Isso porque o que fizemos com o <code>df2</code> foi, conforme visto anteriormente, criar um novo <em>dataframe</em> de fato utilizando o conteúdo de <code>df</code>, enquanto <code>df3</code> acaba por ser um outro nome para o <code>df</code>. <strong>Pode parecer repetitivo, mas é importante que fique clara essa diferença entre as duas funções, para que, quando for analisar seus próprios dados, não ocorram erros que podem consumir um tempo que será importante</strong>.</p>
<hr />
<p>Nessa aula de pandas, vimos algumas coisas que são essenciais ter em mente ao usar a biblioteca para analisar seus dados, além de alguns recursos interessantes. Nas referências abaixo, há uma riqueza de conteúdo para entender melhor sobre os <code>counts</code>, além de mais links para você entender melhor os conceitos de referência e cópia de objetos. Além disso, no último link há um eBook gratuito feito pelos usuários do Stack Overflow para você aprender mais sobre a biblioteca pandas.</p>
<p>Nas próximas aulas, continuaremos a falar sobre aspectos da biblioteca pandas para análise de dados, além de começar a fazer uns <em>plots</em> simples. O início da visualização de dados na série está perto de chegar, não perca!</p>
<p>Um grande abraço e até a próxima aula!</p>
<p><strong>Leia mais:</strong></p>
<ul>
<li><a target="_blank" href="https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.value_counts.html"><strong>Documentação do Pandas sobre value_counts</strong></a></li>
<li><a target="_blank" href="https://re-thought.com/pandas-value_counts/"><strong>8 Python Pandas Value_counts() tricks that make your work more efficient - Re/thought</strong></a></li>
<li><a target="_blank" href="https://towardsdatascience.com/getting-more-value-from-the-pandas-value-counts-aa17230907a6"><strong>Getting more value from the Pandas’ value_counts() - Towards Data Science</strong></a></li>
<li><a target="_blank" href="https://stackoverflow.com/questions/5234126/python-variable-scope-passing-by-reference-or-copy"><strong>Python Variable Scope (passing by reference or copy?) - Stack Overflow</strong></a></li>
<li><a target="_blank" href="https://www.informit.com/articles/article.aspx?p=453682&amp;seqNum=4"><strong>References and Copies - Python Essential Reference - InformIT</strong></a></li>
<li><a target="_blank" href="https://levelup.gitconnected.com/understanding-reference-and-copy-in-python-c681341a0cd8"><strong>Understanding Reference and Copy in Python - Gitconnected</strong></a></li>
<li><a target="_blank" href="https://riptutorial.com/python"><strong>Python - RIP Tutorial</strong></a></li>
<li><a target="_blank" href="https://riptutorial.com/ebook/pandas"><strong>Learning pandas eBook - RIP Tutorial</strong></a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Aula 5 - Análise e visualização de dados em Python - Biblioteca pandas (Parte 1)]]></title><description><![CDATA[Após quatro aulas de introdução teórica e apresentação de bibliotecas, podemos ir à parte prática propriamente dita da série. Iniciaremos utilizando a biblioteca pandas, que é uma biblioteca essencial na análise de dados.
Nessa aula, então, veremos:
...]]></description><link>https://blog.matheusyuri.pro/aula-5-analise-e-visualizacao-de-dados-em-python-biblioteca-pandas-parte-1</link><guid isPermaLink="true">https://blog.matheusyuri.pro/aula-5-analise-e-visualizacao-de-dados-em-python-biblioteca-pandas-parte-1</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[data]]></category><category><![CDATA[python beginner]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Tue, 17 Aug 2021 11:51:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628946222370/sr1vyUqEI.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Após quatro aulas de introdução teórica e apresentação de bibliotecas, podemos ir à parte prática propriamente dita da série. Iniciaremos utilizando a biblioteca pandas, que é uma biblioteca essencial na análise de dados.</p>
<p>Nessa aula, então, veremos:</p>
<ul>
<li>Como importar os dados para um notebook Jupyter através do pandas;</li>
<li>Primeiras análises com o pandas: resumo estatístico, medidas de tendência central e dispersão.</li>
<li>Agrupamentos e fatiamentos no pandas</li>
</ul>
<h2 id="mas-antes-algumas-consideracoes-sobre-os-dados">Mas antes, algumas considerações sobre os dados</h2>
<p>Os dados que utilizaremos durante as aulas estarão sempre disponíveis no <a target="_blank" href="https://github.com/mhalmenschlager/python-biologia">repositório da série no GitHub</a>, para que vocês possam baixar e explorá-los offline, assim como trabalhar com eles na nuvem, através do Google Colaboratory. Além disso, todos os códigos e as respostas dos desafios estarão em uma pasta de notebooks do mesmo repositório; você pode acessá-las quando quiser para ver os <em>outputs</em> e respostas dos desafios. Aproveite também para explorar os notebooks no Google Colab; sempre haverá um botão 'Open in Colab' ou um link para a plataforma nos notebooks do GitHub. Usaremos sempre o Google Colab para as práticas.</p>
<p>Os dados que utilizaremos nessa primeira parte são originados do curso <a target="_blank" href="https://datacarpentry.org/python-ecology-lesson/">"Data Analysis and Visualization in Python for Ecologists"</a>, aula <a target="_blank" href="https://datacarpentry.org/python-ecology-lesson/02-starting-with-data/index.html"><em>Starting with Data</em></a>. Os arquivos são do <a target="_blank" href="https://figshare.com/articles/Portal_Project_Teaching_Database/1314459"><em>Portal Project Teaching Database</em></a> e podem ser encontrados originalmente <a target="_blank" href="https://ndownloader.figshare.com/files/2292172">aqui</a>. Ressalto aqui que os arquivos estão disponibilizados no repositório do GitHub na íntegra, e estão em domínio público; logo, é possível usar os dados livremente. O dicionário de variáveis pode ser consultado tanto na aula original, quanto no notebook dessa aula.</p>
<h2 id="vamos-logo-a-parte-pratica">Vamos logo à parte prática?</h2>
<h3 id="instalacao-e-importacao-do-pandas-para-um-notebook-jupyter-ou-do-google-colaboratory">Instalação e importação do Pandas para um notebook Jupyter (ou do Google Colaboratory)</h3>
<p><strong>Acesse os notebooks práticos por aqui: <a target="_blank" href="https://github.com/mhalmenschlager/python-biologia/blob/main/notebooks/Python_para_Ec%C3%B3logos_1.ipynb">GitHub</a> e <a target="_blank" href="https://colab.research.google.com/drive/1M8wjaKYhNlJR7URUbwaA8jpgGa6_sH4q#scrollTo=gDcvfYddzPnN">Google Colab</a> </strong></p>
<p>A instalação do pandas pode ser necessária se você estiver usando alguma plataforma à parte o Google Colaboratory, que já possui a biblioteca instalada. Para fazer isso, é possível usar o <code>!pip install</code>. Considerada essa parte, podemos fazer a importação usando o comando <code>import</code>.</p>
<pre><code class="lang-python">!pip install pandas <span class="hljs-comment">#Para instalar</span>
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd <span class="hljs-comment">#Para importar ao notebook</span>
</code></pre>
<h3 id="importacao-de-dados">Importação de dados</h3>
<p>O pandas, como já foi relatado em aulas anteriores, possui suporte para importação de vários arquivos de dados (<code>.xlsx</code>, <code>.csv</code>, e <code>.json</code> são alguns exemplos); para cada um deles, existe uma função específica, mas que segue um mesmo padrão: <code>pd.read_type()</code>. O <code>pd</code> é o <em>alias</em> do pandas, e a função que estaremos chamando é <code>read_type()</code>, sendo que é preciso mencionar o tipo de arquivo onde estão os dados. No caso do nosso exemplo, como usaremos o arquivo <code>surveys.csv</code>, é preciso chamar a função <code>pd.read_csv("local do arquivo")</code>.</p>
<pre><code class="lang-python">df = pd.read_csv(<span class="hljs-string">"https://github.com/mhalmenschlager/python-biologia/raw/main/archives/surveys.csv"</span>)
</code></pre>
<p>Assim foi feita a importação dos dados para o notebook; repare que estamos criando um novo objeto através do comando <code>df =</code>. Isso quer dizer que estamos criando um objeto do conjunto de dados que importamos. É importante fazer isso para prosseguirmos aos próximos passos.</p>
<h3 id="primeiras-visualizacoes-com-pandas">Primeiras visualizações com pandas</h3>
<p>A primeira coisa que podemos fazer com o <em>dataframe</em> e o pandas importados ao nosso notebook é verificar como os dados foram importados e como estão dispostos no objeto que criamos anteriormente. Para tanto, podemos usar duas funções: a função <code>head()</code> nos permite ver as cinco primeiras entradas do <code>df</code>; além disso, a função <code>info()</code> nos dá a informação de que tipos de dados há no <em>dataframe</em> e quantos dados são considerados como não-nulos. </p>
<pre><code class="lang-python">df.head() <span class="hljs-comment">#Cinco primeiras entradas</span>
df.info() <span class="hljs-comment">#Tipos de dados existentes</span>
</code></pre>
<p>Após isso, podemos obter também um resumo estatístico dos dados. Isso pode valer tanto para todo o <em>dataframe</em>, quanto para apenas uma coluna ou variável dele. Para isso, usamos a função <code>describe()</code>.</p>
<blockquote>
<p><strong>Que tal fazer você mesmo?</strong></p>
<p>(1) Vimos aqui que a função <code>head()</code> aponta as cinco primeiras entradas do nosso <em>dataframe</em>. Há também uma outra função relacionada a essa chamada <code>tail()</code> O que ela faz?</p>
<p>(2) Ainda sobre a função <code>head()</code>: se quisermos exibir mais de 5 linhas, o que devemos fazer? Será que podemos fazer o mesmo para exibir menos que isso?</p>
<p>Você pode usar o mesmo objeto <code>df</code> para descobrir. <em>As respostas estarão no repositório da série no GitHub e no notebook do Google Colab</em>. </p>
</blockquote>
<pre><code class="lang-python">df.describe() <span class="hljs-comment">#Resumo estatístico de todo o dataframe</span>
df[<span class="hljs-string">'weight'</span>].describe() <span class="hljs-comment">#Resumo estatístico da variável 'weight'</span>
</code></pre>
<h3 id="medidas-de-tendencia-central-e-dispersao-media-mediana-moda-desvio-padrao">Medidas de tendência central e dispersão (média, mediana, moda, desvio-padrão)</h3>
<p>O resumo estatístico, tanto do <em>dataframe</em> inteiro, quanto de uma variável específica, aponta algumas medidas interessantes, tanto de tendência central, quanto de dispersão. Essas medidas são essenciais para começarmos a analisar a variância do conjunto de dados que temos. Mas, e se quisermos fazer uma análise de apenas uma dessas medidas? No pandas, é simples de apontar esses índices em separado: basta usar a fórmula <code>dataframe['variável'].medida()</code>. A seguir há alguns exemplos para que você possa entender melhor:</p>
<pre><code class="lang-python">df[<span class="hljs-string">'weight'</span>].mean() <span class="hljs-comment">#Para descobrir a média</span>
df[<span class="hljs-string">'weight'</span>].median() <span class="hljs-comment">#Para descobrir a mediana</span>
df[<span class="hljs-string">'weight'</span>].std() <span class="hljs-comment">#Para descobrir o desvio-padrão</span>
</code></pre>
<h3 id="agrupamentos-no-pandas">Agrupamentos no pandas</h3>
<p>Algumas variáveis dentro do nosso <em>dataset</em> de exemplo são consideradas como categóricas; a partir disso, podemos fazer alguns exercícios envolvendo essas variáveis utilizando o método de agrupamento no pandas.</p>
<p>Por exemplo: sabendo da existência da variável <code>sex</code> dentro do <em>dataset</em> e, importada essa mesma variável pro nosso <em>dataframe</em>, quantos registros de cada sexo biológico constam no nosso conjunto de dados? Para descobrir isso, podemos utilizar a função <code>value_counts()</code>, assim:</p>
<pre><code class="lang-python">df[<span class="hljs-string">'sex'</span>].value_counts()
</code></pre>
<p>No entanto, também temos outro recurso do pandas com o qual podemos trabalhar com agrupamentos de variáveis categóricas: o <code>groupby()</code>. Com ele, podemos ir mais além da contagem e usar medidas de tendência central e dispersão para observar variâncias de uma variável por outra. A fórmula fica assim: <code>dataframe.groupby('variável1')['variável2'].medida()</code>. </p>
<p>Para entender melhor: imagine que queremos descobrir a média dos pesos das nossas amostragens, agrupando-as por sexo. Para descobrir isso, podemos utilizar a fórmula citada antes, assim:</p>
<pre><code class="lang-python">df.groupby(<span class="hljs-string">'sex'</span>)[<span class="hljs-string">'weight'</span>].mean()
</code></pre>
<p>Perceba como as variáveis estão posicionadas na linha de código; a variável <code>sex</code>, que é a que agruparemos, está na primeira posição, em parênteses, associada com a função <code>groupby()</code>, enquanto que a variável <code>weight</code>, de onde tiraremos as médias, vem logo depois, em colchetes. A mesma fórmula pode ser usada para tirar outras medidas com outros agrupamentos.</p>
<blockquote>
<p><strong>Que tal fazer você mesmo?</strong></p>
<p>Com o mesmo <em>dataframe</em> podemos então comparar mais medidas agrupando as amostras por sexo. Será que você consegue comparar essa categoria:</p>
<ul>
<li>por medianas de peso?</li>
<li>por médias de comprimento do retropé (hindfoot)? E qual o máximo do comprimento para cada sexo?</li>
</ul>
<p>Você pode ainda usar o objeto <code>df</code> para descobrir. <em>As respostas estarão no repositório da série no GitHub e no notebook do Google Colab</em>. </p>
</blockquote>
<h3 id="filtragem-do-conjunto-de-dados-por-fatiamento">Filtragem do conjunto de dados por fatiamento</h3>
<p>Na ciência de dados, há uma prática conhecida por <em>slicing</em> ou <em>fatiamento</em>, onde há a possibilidade de fazermos uma filtragem do conjunto de dados, podendo criar inclusive <em>subsets</em> do conjunto para que possamos explorar e visualizar melhor os dados mais adiante. Esse fatiamento pode ser feito tanto com linhas, quanto por colunas de uma certa tabela.</p>
<p>Usemos o nosso objeto <code>df</code> para entender melhor essa prática. Se quisermos fazer um fatiamento por linhas do <em>dataframe</em>, podemos utilizar uma fórmula simples: <code>df[linha início: linha fim +1]</code> Um detalhe importante a ser mencionado aqui é que a indexação do Python, ao contrário de algumas outras linguagens, começa pelo 0. Então, se quisermos fatiar o <em>dataframe</em> da primeira até a sétima linha, podemos fazer assim:</p>
<pre><code class="lang-python">df_linha = df[<span class="hljs-number">0</span>:<span class="hljs-number">7</span>] <span class="hljs-comment">#Linha de início (0): linha final (6)+1</span>
</code></pre>
<p>O fatiamento de colunas também é fácil; apenas em vez de usarmos números, mencionaremos os nomes das colunas. A fórmula é <code>df['nome da coluna']</code> para fatiar apenas uma coluna, e <code>df[['col1', 'col2', 'col3'...'colN']]</code> para uma lista de colunas. Repare na duplicação de colchetes quando usamos a segunda fórmula; isso porque estamos usando o caractere de lista do Python para fazer isso, o que não é necessário quando queremos separar apenas uma coluna.</p>
<pre><code class="lang-python">df_coluna = df[<span class="hljs-string">'weight'</span>] <span class="hljs-comment">#Uma coluna</span>
df_coluna = df[[<span class="hljs-string">'weight'</span>, <span class="hljs-string">'sex'</span>]] <span class="hljs-comment">#Mais de uma coluna</span>
</code></pre>
<hr />
<p>Até agora, vimos um pouco de análise de dados com o pandas, assunto no qual nos estenderemos por mais aulas. Nas referências abaixo, assim como no hyperlinks ao longo do texto, terá mais conteúdo para você poder praticar os conceitos apresentados, além de poder avançar um pouco mais na biblioteca pandas. Não se esqueça de dar uma olhada no notebook das aulas, onde você pode ver os <em>outputs</em> de cada bloco de código citado, as resoluções dos desafios e explorar a linguagem Python por si.</p>
<p>Um grande abraço e até a próxima aula!</p>
<p><strong>Leia mais:</strong></p>
<ul>
<li><a target="_blank" href="https://medium.com/@enzodel1991/as-principais-fun%C3%A7%C3%B5es-do-pandas-que-todos-deveriam-saber-60a1899324e6"><strong>As principais funções do pandas que todo mundo deveria saber - Enzo Delcompare</strong></a></li>
<li><a target="_blank" href="https://lnkd.in/d_sbZ2R"><strong>Guias sobre Python - Odemir Delpieri Jr. no Linkedin</strong></a></li>
<li><a target="_blank" href="https://colab.research.google.com/drive/1PyWEN7031Brmrey2zfh6DGPQk3LY4CPg"><strong>Dicas de Manipulação de Dados com pandas - Vitor Diego Ramos</strong></a></li>
<li><a target="_blank" href="https://towardsdatascience.com/python-for-data-science-basics-of-pandas-5f8d9680617e"><strong>Python for Data Science - A Guide to pandas -  Towards Data Science</strong></a></li>
<li><a target="_blank" href="https://realpython.com/learning-paths/pandas-data-science/"><strong>Pandas for Data Science (Learning Path) - Real Python</strong></a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Aula 4 - Análise e visualização de dados em Python - Apresentando as bibliotecas]]></title><description><![CDATA[Após uma introdução sobre os principais elementos, tipos de dados, e funções que compõem a linguagem Python, chegou o momento da apresentação às chamadas bibliotecas. A partir desse momento, você começará a entender como é possível usar o Python para...]]></description><link>https://blog.matheusyuri.pro/aula-4-analise-e-visualizacao-de-dados-em-python-apresentando-as-bibliotecas</link><guid isPermaLink="true">https://blog.matheusyuri.pro/aula-4-analise-e-visualizacao-de-dados-em-python-apresentando-as-bibliotecas</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[data]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Thu, 12 Aug 2021 11:23:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628766917810/Re0aOI4HJ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Após uma introdução sobre os principais elementos, tipos de dados, e funções que compõem a linguagem Python, chegou o momento da apresentação às chamadas bibliotecas. A partir desse momento, você começará a entender como é possível usar o Python para analisar e visualizar mais efetivamente seus dados, usando os recursos que realmente importam.</p>
<p>Nesta aula, portanto, veremos: </p>
<ul>
<li>O que são bibliotecas;</li>
<li>Como instalar e importar bibliotecas no ambiente Jupyter Notebook;</li>
<li>Quais bibliotecas são importantes para trabalhar com dados.</li>
</ul>
<h2 id="o-que-sao-bibliotecas-afinal">O que são bibliotecas afinal?</h2>
<p>Se você já deu uma pesquisada sobre assuntos e características envolvendo a linguagem Python (ou outras linguagens, como o R), deve ter visto algumas fontes escrevendo algo sobre as ditas 'bibliotecas'.  </p>
<p><a target="_blank" href="https://pt.wikipedia.org/wiki/Biblioteca_(computa%C3%A7%C3%A3o"><strong>Bibliotecas</strong></a>), em Python, são um conjunto de linhas de códigos construídas para um propósito específico (acessos a bases de dados, cálculos, modelos... o que você puder imaginar) e que podem ser utilizadas para reduzir o tamanho dos códigos escritos num processo de programação, além do tempo que se leva na escrita e organização desses códigos, uma vez que são reutilizáveis. </p>
<p>O Python, por si só, possui o que é conhecido como <a target="_blank" href="https://pt.wikibooks.org/wiki/Python/Bibliotecas_padr%C3%A3o"><strong>Biblioteca Padrão</strong></a>, que é um conjunto de módulos essenciais e úteis para o seu funcionamento. Essa biblioteca já vem junto com o pacote que é instalado do site oficial, ou seja, não é preciso nenhuma ação posterior para tê-la em sua máquina. Para outras bibliotecas, dependendo do caso, é preciso fazer a instalação antes de usá-las. E como se faz isso?</p>
<h2 id="como-instalar-e-importar-bibliotecas-em-um-ambiente-jupyter-notebook">Como instalar  e importar bibliotecas em um ambiente Jupyter Notebook</h2>
<p>No nosso caso, independente de ser no ambiente Jupyter Notebook instalado com o pacote Anaconda, ou o ambiente do Google Colaboratory (que é inspirado na iniciativa Jupyter), podemos utilizar comando semelhante para o caso de querer instalar alguma biblioteca, o <code>pip</code>: </p>
<pre><code class="lang-python">!pip install PackageName
!pip install geopandas <span class="hljs-comment">#Um exemplo de biblioteca para instalar</span>
</code></pre>
<p>Para descobrir quais bibliotecas estão instaladas no ambiente no qual você trabalhará com seus dados, existem comandos como o <code>pip freeze</code>e o <code>help()</code>; este último também serve para acionar a ajuda de qualquer biblioteca já disponível no ambiente (inclusive a chamada Biblioteca Padrão do Python).</p>
<pre><code class="lang-python">pip freeze
help(<span class="hljs-string">"modules"</span>)
</code></pre>
<p>No caso de a biblioteca já ter sido instalada, o que precisamos fazer somente é importá-la para o ambiente antes de começarmos a trabalhar; por uma questão de conveniência, sobretudo, nem o Python, nem o ambiente Jupyter carregam todas as bibliotecas que já possuem instaladas. Para tanto, usamos a função <code>import</code>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
<span class="hljs-keyword">import</span> geopandas <span class="hljs-keyword">as</span> gpd
<span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt
<span class="hljs-keyword">import</span> seaborn <span class="hljs-keyword">as</span> sns
<span class="hljs-keyword">import</span> folium
</code></pre>
<p>Repare que, nesse comando, utilizamos um argumento <code>as</code>para importar, seguido de uma sigla. Tal atributo serve como um <em>alias</em> da biblioteca a ser importada, facilitando o processo; em vez de escrevermos <code>matplotlib.pyplot</code> toda vez que queremos usar uma função da biblioteca, apenas escrevemos <code>plt</code>e a função que queremos para fazer funcionar (isso será melhor compreendido quando partirmos para a pare prática/analítica da série, não se preocupe). Nem todas as bibliotecas terão esse <em>alias</em>; nos notebooks da série, essas abreviações aparecerão quando for conveniente.</p>
<p>O uso dessas bibliotecas também é bem simples: na linha de comando, se utiliza a ordem <code>biblioteca.função()</code>. O mesmo para a criação de objetos, quando necessário, apenas atribuindo uma variável ao mesmo.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
dataframe = pd.read_csv(<span class="hljs-string">"exemplo.csv"</span>)
</code></pre>
<h2 id="as-bibliotecas-mais-importantes-para-trabalhar-com-dados">As bibliotecas mais importantes para trabalhar com dados</h2>
<p>Agora que sabemos o que são bibliotecas, além como proceder à instalação e importação das mesmas, podemos fazer a apresentação das bibliotecas que você poderá utilizar para trabalhar com seus dados. Vale ressaltar que, assim como o Python propriamente dito, as bibliotecas citadas são gratuitas e de código-aberto; então, você pode usá-las livremente a qualquer momento.</p>
<h3 id="pandas">pandas</h3>
<p><img src="https://pandas.pydata.org/static/img/pandas.svg" alt="img" /></p>
<pre><code class="lang-python">!pip install pandas
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
</code></pre>
<p>De início, podemos mencionar a biblioteca <strong>pandas </strong>(assim mesmo, em <em>lower case</em>). Ela é uma das mais conhecidas bibliotecas de análise de dados em Python, e geralmente é a primeira a ser apresentada aos futuros cientistas de dados. A razão para isso é simples: o pandas, além de ser uma biblioteca completa para análise de dados, é fácil de manusear. Você pode trabalhar com variados tipos de arquivos de dados, como JSON e Excel (<code>.csv</code>, <code>.xlsx</code>). É nessa biblioteca que a série baseará suas primeiras aulas práticas.</p>
<p>Você pode consultar a documentação do pandas <a target="_blank" href="https://pandas.pydata.org/docs/">aqui</a>, além de verificar a seção dedicada ao projeto pandas no <a target="_blank" href="https://pypi.org/project/pandas/">PyPI</a>.</p>
<h3 id="numpy">NumPy</h3>
<p><img src="https://github.com/numpy/numpy/blob/main/branding/logo/primary/numpylogo.png?raw=true" alt="numpylogo.png" /></p>
<pre><code class="lang-python">!pip install numpy
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np
</code></pre>
<p>O <strong>NumPy</strong> também é uma das bibliotecas basais para quem quer lidar com dados no Python. Essa biblioteca trabalha, principalmente, com arranjos de matrizes e vetores, cobrindo todas as funções de álgebra linear, além de poder trabalhar com manipulação de imagens, estatística, e operações matemáticas. Isso faz com que o NumPy esteja presente nas linhas de código de várias bibliotecas utilizadas no mundo da ciência de dados, como o pandas. Não é à toa que, segundo o site oficial do NumPy, <em>"quase todo cientista que usa Python se vale do poder do NumPy"</em>.</p>
<p>Você pode saber mais sobre o ecossistema do NumPy acessando <a target="_blank" href="https://numpy.org/">a página inicial</a>, e verificar o poder da biblioteca <a target="_blank" href="https://numpy.org/doc/stable">na sua documentação</a>.</p>
<h3 id="geopandas">GeoPandas</h3>
<p><img src="https://geopandas.org/_images/geopandas_logo.png" alt="geopandas-logo" /></p>
<pre><code class="lang-python">!pip install geopandas
<span class="hljs-keyword">import</span> geopandas <span class="hljs-keyword">as</span> gpd
</code></pre>
<p>Outra biblioteca a qual a série dará atenção é a <strong>GeoPandas</strong>. Como o nome e o logo já entregam, a biblioteca se baseia em pandas, sendo especializada na importação de dados geográficos para o ambiente; então, é com essa biblioteca que você pode trabalhar com as coordenadas que estão juntas dos seus dados de coleta, por exemplo. Também é possível trabalhar com shapefiles (arquivos <code>.shp</code>, <code>.shx</code>, <code>.dbf</code>...), além de dados em formato GeoJSON.</p>
<p>Verifique a documentação do GeoPandas <a target="_blank" href="https://geopandas.org/docs.html">aqui</a> para saber mais sobre as possibilidades de se trabalhar com essa biblioteca.</p>
<h3 id="matplotlib">Matplotlib</h3>
<p><img src="https://matplotlib.org/stable/_images/sphx_glr_logos2_003.png" alt="logos2" /></p>
<pre><code class="lang-python">!pip install matplotlib
<span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt
</code></pre>
<p>O <strong>Matplotlib</strong> é a principal biblioteca para visualização de dados no Python. Com ela, é possível plotar os mais diversos gráficos, tendo a capacidade de administrar desde o título do gráfico, até escalas, cores e fontes. A parte de visualização de dados do pandas é baseada no Matplotlib, sendo que muitas vezes trabalham juntas.</p>
<p>A documentação do Matplotlib pode ser vista <a target="_blank" href="https://matplotlib.org/stable/contents.html">aqui</a>.</p>
<h3 id="seaborn">Seaborn</h3>
<p><img src="https://seaborn.pydata.org/_images/logo-wide-lightbg.svg" alt="_images/logo-wide-lightbg.svg" /></p>
<pre><code class="lang-python">!pip install seaborn
<span class="hljs-keyword">import</span> seaborn <span class="hljs-keyword">as</span> sns
</code></pre>
<p>Em matéria de visualização de dados, o <strong>Seaborn</strong> é uma ótima opção. A biblioteca permite ir mais além dos <em>plots</em> do Matplotlib, gerando gráficos com um estilo mais elegante e com poucas linhas de código. </p>
<p>Na <a target="_blank" href="https://seaborn.pydata.org/index.html">página oficial da biblioteca</a>, você pode explorar todas as possibilidades de visualização de dados que o Seaborn oferece.</p>
<h2 id="onde-encontrar-outras-bibliotecas-uteis-para-dados">Onde encontrar outras bibliotecas úteis para dados</h2>
<h3 id="python-package-index">Python Package Index</h3>
<p><img src="https://pypi.org/static/images/logo-large.6bdbb439.svg" alt="img" /></p>
<p>Para encontrar e se atualizar sobre outras bibliotecas úteis para trabalhar com seus dados, além dos projetos a elas associados, o <a target="_blank" href="https://pypi.org/"><strong>Python Package Index</strong></a> (PyPI) é uma ótima referência. Lá você pode buscar por mais de 320 mil projetos baseados em Python nas mais variadas áreas do conhecimento, além de encontrar várias instruções de como instalar e atualizar bibliotecas.</p>
<hr />
<p>Nesta aula da série, vimos o que são bibliotecas, como lidar com elas, além de uma apresentação rápida sobre as bibliotecas mais importantes para trabalhar com dados em Python. Uma vez conhecida essa questão, estamos prontos para começar a parte 'mão na massa' da série. A partir da próxima aula, conceitos que foram apresentados nos posts introdutórios começaram a ser assentados na sua mente de uma das melhores formas possíveis: praticando, sem muitos rodeios. Em cada início de aula serão apresentados, caso necessário, os conjuntos de dados, ou <em>datasets</em>, que serão utilizados; é a partir deles que faremos nossas primeiras análises. </p>
<p>A primeira, e principal, biblioteca que usaremos nessa série, será o pandas. Recomendo que, antes de prosseguir, você dê uma olhada na página oficial e na documentação da biblioteca; lá estarão aspectos que, por variadas questões, não conseguirão ser cobertas aqui por completo. Faça o mesmo com as outras bibliotecas, além de verificar o site do PyPI.</p>
<p>Bora começar a praticar análise e visualização de dados em Python juntos?</p>
<p>Caso queira, deixe um feedback ou sua dúvida em um comentário ou mensagem, para que nosso aprendizado seja cada vez mais amplo.</p>
<p>Um forte abraço e até a próxima aula!</p>
<hr />
<h2 id="para-ler-mais">Para ler mais:</h2>
<ul>
<li><a target="_blank" href="https://www.voitto.com.br/blog/artigo/principais-bibliotecas-python">Conheça 11 bibliotecas Python aplicadas na Ciência de Dados - Voitto</a></li>
<li><a target="_blank" href="https://terminalroot.com.br/2019/12/as-30-melhores-bibliotecas-e-pacotes-python-para-iniciantes.html">As 30 melhores bibliotecas e pacotes Python para Iniciantes - Terminal Root</a></li>
<li><a target="_blank" href="https://www.pythondaddy.com/python/how-to-list-all-installed-packages-in-python-in-4-ways/">How to List all installed Packages in Python in 4 Ways - Python Daddy</a></li>
<li><a target="_blank" href="https://www.geeksforgeeks.org/what-is-the-difference-between-pythons-module-package-and-library/#:~:text=What%20is%20the%20difference%20between%20Python's%20Module%2C%20Package%20and%20Library%3F,-Difficulty%20Level%20%3A%20Medium&amp;text=Module%3A%20The%20module%20is%20a,concept%20called%20Package%20in%20Python.">What is the difference between Python’s Module, Package and Library? - GeeksforGeeks</a></li>
<li><a target="_blank" href="https://medium.com/@shivangisareen/for-anyone-using-jupyter-notebook-installing-packages-18a9468d0c1c">For Anyone Using Jupyter Notebook — Installing Packages - Shivangi Sareen</a></li>
<li><a target="_blank" href="https://jakevdp.github.io/blog/2017/12/05/installing-python-packages-from-jupyter/">Installing Python Packages from a Jupyter Notebook - Pythonic Perambulations</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Aula 3 - Introdução às funções em Python]]></title><description><![CDATA[Até agora, foram apresentadas de forma teórica e prática alguns dos principais elementos do Python: operações, tipos de dados, sequências, e dicionários. Nessa aula, será feita uma introdução às funções na linguagem Python.
Então, o que será visto aq...]]></description><link>https://blog.matheusyuri.pro/aula-3-introducao-as-funcoes-em-python</link><guid isPermaLink="true">https://blog.matheusyuri.pro/aula-3-introducao-as-funcoes-em-python</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[data analysis]]></category><category><![CDATA[data]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Thu, 05 Aug 2021 17:30:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628181181709/sJS7FfjsY.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Até agora, foram apresentadas de forma teórica e prática alguns dos principais elementos do Python: <strong>operações</strong>, <strong>tipos de dados</strong>, <strong>sequências</strong>, e <strong>dicionários</strong>. Nessa aula, será feita uma introdução às funções na linguagem Python.</p>
<p>Então, o que será visto aqui:</p>
<ul>
<li>O que são funções, e para que servem;</li>
<li>Como escrevê-las em Python.</li>
</ul>
<h2 id="o-que-sao-funcoes">O que são funções?</h2>
<p>Em várias linguagens de programação, <strong>funções</strong> são recursos que muito auxiliam na hora de meter a mão na massa; elas são <strong>blocos de código</strong> que performam tarefas que, normalmente, precisam ser executadas mais de uma vez dentro de uma aplicação. Assim, um algoritmo ou notebook fica menor, mais rápido de executar e, sobretudo, mais legível a outros usuários.</p>
<p>As funções também servem para a criação de bibliotecas em Python. No contexto de análise de dados, há bibliotecas que possuem funções prontas para calcular medidas de variância, de dispersão, tendência central, similaridade, entre outros (citam-se aqui exemplos que podem ser encontrados no <a target="_blank" href="https://scipy-cookbook.readthedocs.io/">cookbook da biblioteca SciPy</a>, além da <a target="_blank" href="https://numpy.org/doc/stable/">documentação do NumPy</a>); além disso, para ecólogos, haverá funções que executam os principais cálculos necessários para mensurar diversidade, abundância, dominância, e tantas outras operações mais as quais os profissionais precisam lançar mão. Nesse caso em específico, a <a target="_blank" href="https://ecopy.readthedocs.io/en/latest/">documentação da biblioteca EcoPy</a> proporciona um leque de cálculos ecológicos, sendo cada um deles descrito em detalhes, para entendimento dos parâmetros e comandos usados.</p>
<h2 id="como-criar-funcoes-no-python">Como criar funções no Python</h2>
<p>Uma função em Python é definida por três partes: <strong>nome</strong>, <strong>parâmetros</strong>, e <strong>corpo (ou comandos)</strong>. Nós podemos <strong>definir uma função</strong> usando essa sintaxe:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">nome</span>(<span class="hljs-params"> parâmetros </span>):</span>
    comandos
</code></pre>
<p>Aqui vemos que a definição de uma função é feita usando a palavra-chave <a target="_blank" href="https://docs.python.org/3/tutorial/controlflow.html#defining-functions"><code>def</code></a>. Você pode colocar qualquer nome para as funções que está criando, ao colocá-lo na posição <code>nome</code>; no entanto, você não pode usar um nome que é considerado <a target="_blank" href="https://docs.python.org/pt-br/3/reference/lexical_analysis.html#keywords">palavra reservada</a>. Os parâmetros vão especificar qual informação, caso haja alguma, é preciso providenciar para que a função seja usada. Em outra palavras, os parâmetros dizem o que a função precisa para executar tarefas. Observe também a presença dos dois pontos (<code>:</code>); isso indica que o código que está nas linhas seguidas a ele faz parte da função que será criada. As linhas seguintes aparecerão avançadas em relação à primeira linha; isso é o que chamamos de <a target="_blank" href="http://www.del.ufrj.br/~lucas.frucht/indentacao.pdf"><strong>indentação</strong></a>, e é uma forma de respeito à sintaxe da linguagem que estamos usando.</p>
<p>Para podemos executar a função, devemos simplesmente chamar o seu nome e passar os parâmetros. A lista de parâmetros pode ser vazia, ter apenas um parâmetro, ou ter mais de um parâmetro, sempre separados por vírgulas. Independente disso, os parênteses são obrigatórios no momento de definir uma função. </p>
<p>Vamos a um breve exemplo prático, para entender melhor:</p>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_func</span>(<span class="hljs-params">a, b</span>):</span>
    resultado = a + b
    <span class="hljs-keyword">return</span> resultado
z = add_func(<span class="hljs-number">10</span>, <span class="hljs-number">12</span>)
print(z)
</code></pre>
<p>Neste bloco de código, estamos fazendo duas coisas: definir uma função e criar uma variável chamando essa função. O nome dessa função é <code>add_func</code>, que possui dois parâmetros, <code>a</code>e <code>b</code>. Dentro da função há dois comandos: <code>resultado</code>e o <code>return resultado</code>; isso quer dizer que, no caso dessa função, se solicitará a soma dos dois parâmetros já citados (<code>a + b</code>) e, para expressar essa soma, a função dará um retorno (<a target="_blank" href="https://pt.stackoverflow.com/questions/115335/o-que-o-return-faz-em-python"><code>return</code></a>) com o resultado.</p>
<p>A variável <code>z</code> possuirá como valor o resultado do uso da função <code>add_func</code>, tendo como parâmetros os números <code>10</code> e <code>12</code>. Uma vez criada, podemos verificar qual será o valor da variável <code>z</code>, usando a função <code>print(z)</code>. O resultado sairá conforme está no output abaixo:</p>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">22</span>
</code></pre>
<hr />
<p>O assunto referente às funções pode se estender bem mais, uma vez que funções podem comportar mais de um parâmetro ou comando, mas não nos ateremos muito a isso. O objetivo aqui é entender como se faz uma função, para que, mais à frente, consigamos entender melhor como trabalhar com as bibliotecas Python que serão apresentadas na série.</p>
<p>Com isso, já temos um arcabouço de como o Python funciona, com seus elementos principais e funções. Nas próximas aulas, começará a parte de mexer com dados; é justamente aí que o Python fica bem mais interessante.</p>
<p>Aproveite para dar seu feedback, e nos vemos nas próximos posts da série!</p>
<h2 id="para-ler-mais"><strong>Para ler mais:</strong></h2>
<ul>
<li><strong><a target="_blank" href="https://www.devmedia.com.br/funcoes-em-python/37340">Como criar funções em Python - DevMedia</a></strong></li>
<li><strong><a target="_blank" href="https://panda.ime.usp.br/pensepy/static/pensepy/05-Funcoes/funcoes.html#:~:text=Em%20Python%2C%20uma%20fun%C3%A7%C3%A3o%20%C3%A9,imaginamos%20uma%20solu%C3%A7%C3%A3o%20do%20problema.">Funções - Como pensar como um cientista da computação - IME-USP</a></strong></li>
<li><strong><a target="_blank" href="https://docs.python.org/pt-br/3/reference/lexical_analysis.html#">Documentação Python - Análise léxica</a></strong></li>
<li><strong><a target="_blank" href="https://docs.python.org/pt-br/3/tutorial/controlflow.html#defining-functions">Documentação Python - Definindo funções</a></strong></li>
<li><strong><a target="_blank" href="https://geo-python-site.readthedocs.io/en/latest/notebooks/L4/functions.html">Functions - Geo-Python</a></strong></li>
<li><strong><a target="_blank" href="https://www.w3schools.com/python/python_functions.asp">Python Functions -  W3Schools</a></strong></li>
<li><strong><a target="_blank" href="https://www.datacamp.com/community/tutorials/functions-python-tutorial">Python Functions: How to Call &amp; Write Functions - Datacamp</a></strong></li>
<li><strong><a target="_blank" href="https://realpython.com/defining-your-own-python-function/">Defining Your Own Python Function - Real Python</a></strong></li>
<li><strong><a target="_blank" href="https://swcarpentry.github.io/python-novice-inflammation/08-func/index.html">Creating Functions - Programming with Python</a></strong></li>
<li><strong><a target="_blank" href="https://www.letscode.com.br/blog/funcoes-e-mais-funcoes-em-python">Funções e mais funções em Python - Let's Code</a></strong></li>
</ul>
<h2 id="literatura-recomendada"><strong>Literatura recomendada:</strong></h2>
<ul>
<li>Capítulo 8 do <em>Curso Intensivo de Python</em>, de Eric Matthes (<a target="_blank" href="http://libgen.rs/book/index.php?md5=1C13103D7B9B54DDD8EFAC70ACA10DA1">Library Genesis</a>)</li>
<li>Capítulo 2 do <em>Data Science do Zero</em>, de Joel Grus (<a target="_blank" href="http://libgen.rs/book/index.php?md5=EE6D1DFB6DDF4F53391557E3E0C97000">Library Genesis</a>)</li>
<li>Capítulos 3 e 4 do <em>Learn to Program with Python 3</em>, de Irv Kalb (<a target="_blank" href="http://libgen.rs/book/index.php?md5=55896AF2DBCBED4A3FB213A69AD32FA8">Library Genesis</a>)</li>
<li>Capítulo 3 do <em>Basic Core Python Programming</em>, de Meenu Kohli (<a target="_blank" href="http://libgen.rs/book/index.php?md5=CDE2BCEA2E13C41D0D9CC160BF9E3C4B">Library Genesis</a>)</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Aula 2 - Introdução aos elementos do Python]]></title><description><![CDATA[Passada a introdução teórica, podemos nos aprofundar em uma parte introdutória mais prática do Python, com algumas linhas de código. Nessa aula, veremos:

Operações básicas no Python: adição, subtração, multiplicação, divisão, potenciação, e módulo a...]]></description><link>https://blog.matheusyuri.pro/aula-2-introducao-aos-elementos-do-python</link><guid isPermaLink="true">https://blog.matheusyuri.pro/aula-2-introducao-aos-elementos-do-python</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[data]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Thu, 05 Aug 2021 17:29:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628106376954/DyzW_VZQ2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Passada a introdução teórica, podemos nos aprofundar em uma parte introdutória mais prática do Python, com algumas linhas de código. Nessa aula, veremos:</p>
<ul>
<li>Operações básicas no Python: adição, subtração, multiplicação, divisão, potenciação, e módulo aritmético;</li>
<li>Operações de lógica e comparação;</li>
<li>Tipos de dados em Python: <em>strings</em>, <em>integers</em>, e <em>floats</em>;</li>
<li>Sequências em Python: listas e tuplas;</li>
<li>Dicionários.</li>
</ul>
<h2 id="operacoes-basicas-em-python">Operações básicas em Python</h2>
<p>Como foi dito na aula anterior, uma das coisas mais básicas para fazer com a linguagem Python é usá-la como uma "calculadora científica", fazendo operações matemáticas básicas com uma linha de código somente. Aqui estão alguns exemplos:</p>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">2</span> + <span class="hljs-number">2</span> <span class="hljs-comment">#Adição (veja 'NOTA 1' para entender o papel do '#')</span>
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">4</span>
</code></pre>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">5</span> - <span class="hljs-number">8</span> <span class="hljs-comment">#Subtração</span>
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">3</span>
</code></pre>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">6</span> * <span class="hljs-number">2</span> <span class="hljs-comment">#Multiplicação</span>
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">12</span>
</code></pre>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">50</span> / <span class="hljs-number">5</span> <span class="hljs-comment">#Divisão</span>
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">10</span>
</code></pre>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">2</span> ** <span class="hljs-number">2</span> <span class="hljs-comment">#Potenciação</span>
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">4</span>
</code></pre>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">13</span> % <span class="hljs-number">5</span> <span class="hljs-comment">#Módulo aritmético (para entender do que se trata, veja 'NOTA 2')</span>
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">3</span>
</code></pre>
<h2 id="operacoes-de-logica-comparacao-e-identidade">Operações de lógica, comparação, e identidade</h2>
<p>Nós podemos também utilizar operadores de lógica e comparação (<code>&lt;, &gt;, ==, !=, &lt;=, &gt;=</code>) em uma só linha de código em Python:</p>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">3</span> &gt; <span class="hljs-number">4</span>
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python"><span class="hljs-literal">False</span>
</code></pre>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">6</span> == <span class="hljs-number">6</span>
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python"><span class="hljs-literal">True</span>
</code></pre>
<p>Além disso, podemos escrever operações de identidade (<code>and, or, not</code>) e obter resultados:</p>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python"><span class="hljs-literal">True</span> <span class="hljs-keyword">and</span> <span class="hljs-literal">True</span>
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python"><span class="hljs-literal">True</span>
</code></pre>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python"><span class="hljs-literal">True</span> <span class="hljs-keyword">and</span> <span class="hljs-literal">False</span>
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python"><span class="hljs-literal">False</span>
</code></pre>
<p>Estes resultados obtidos (<code>True</code> e <code>False</code>) são dados que chamamos de booleanos (<code>boolean</code>). Inclusive, é sobre os tipos de dados que falaremos em seguida.</p>
<h2 id="tipos-de-dados-em-python">Tipos de dados em Python</h2>
<p>Uma das coisas que também está entre as mais básicas no Python é a associação de valores à variáveis. Isso quer dizer que, quando introduzimos dados em um ambiente ou notebook, devemos nomeá-los, para que possamos identificá-los ao trabalhar com funções e bibliotecas. Essa associação é feita usando o operador de atribuição <code>=</code>. Um detalhe: não confunda esse operador com o de comparação <code>==</code>.</p>
<p>Por exemplo:</p>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python">texto = <span class="hljs-string">"Exemplo de texto"</span>  <span class="hljs-comment"># Um exemplo de linha (string)</span>
numero = <span class="hljs-number">42</span>  <span class="hljs-comment"># Um exemplo de número inteiro (integer)</span>
pi_valor = <span class="hljs-number">3.1415</span>  <span class="hljs-comment"># Um exemplo de número decimal (float)</span>
</code></pre>
<p>Junto do exemplo está uma exposição de alguns tipos de dados que podemos utilizar em Python:</p>
<ul>
<li>Linhas (<code>string</code>): são sequências de caracteres, que podem ser letras, números (quando dentro de aspas), pontuações e até emojis (🤔);</li>
<li>Números inteiros (<code>integer</code>): números inteiros que podem ser utilizados em funções e operações;</li>
<li>Números decimais (<code>float</code>): números separados por pontos, que também podem ser utilizados em funções ou operações.</li>
<li>Dados booleanos (<code>boolean</code>): são dados que retornam após operações lógicas ou de comparação. Basicamente, apontam se uma operação como as citadas é procedente ou não, verdadeira ou falsa. Também podem se referir a um dado ausente ou presente num dado dataframe ou dataset. No Python, os dados booleanos aparecem como <code>True</code> ou <code>False</code>.</li>
</ul>
<p>Tudo que está em Python possui um tipo, e é importante sempre ter em mente quais são os tipos de dados que estão sendo utilizados, para evitar erros de interpretação ou incompatibilidades. Para descobrir qual o tipo de um objeto, lançamos mão da função <code>type()</code>.</p>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python">type(texto)
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python">&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> '<span class="hljs-title">str</span>'&gt;</span>
</code></pre>
<p>Nós podemos ver o valor de alguma coisa usando a função <code>print()</code>.</p>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python">texto_novo = <span class="hljs-string">'Um outro exemplo de texto'</span>
print(texto_novo)
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python">Um outro exemplo de texto
</code></pre>
<h2 id="sequencias-em-python-listas-e-tuplas">Sequências em Python: Listas e tuplas</h2>
<p>Nesta parte da aula, veremos como lidar com uma sequência ordenada de elementos. Temos dois casos a cobrir: listas e tuplas.</p>
<ul>
<li><p>Listas: são sequências simples de elementos, separados por vírgulas. Criamos uma lista usando colchetes (<code>[]</code>).</p>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python">lista = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>]
</code></pre>
<p>Em uma sequência ordenada como essa, cada elemento é acessível por meio de um índice. Importante notar que, em Python, os índices sempre iniciam em 0, em vez de 1. Ou seja, para acessar o primeiro elemento, é necessário chamar o número 0. </p>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python">lista[<span class="hljs-number">0</span>]
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">1</span>
</code></pre>
</li>
<li><p>Tuplas: também são sequência simples de elementos, tais como as listas; a diferença é que, nesse caso, os elementos dentro de uma tupla são imutáveis (não podem ser mudados após sua criação). Criamos uma tupla usando parênteses.</p>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python">tupla = (<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>)
outra_tupla = (<span class="hljs-string">'um'</span>, <span class="hljs-string">'dois'</span>, <span class="hljs-string">'três'</span>, <span class="hljs-string">'quatro'</span>)
</code></pre>
</li>
</ul>
<h2 id="dicionarios">Dicionários</h2>
<p>Em Python, consideramos como dicionários os objetos que possuem um par de outros objetos em seu interior. Também funcionam como as listas e tuplas, mas, em vez de terem índices, são organizados por chaves - é como se fosse uma etiqueta única ou um nome do objeto.</p>
<p>Para entender como funciona:</p>
<pre><code class="lang-python">ordem = {<span class="hljs-string">'um'</span>: <span class="hljs-string">'primeiro'</span>, <span class="hljs-string">'dois'</span>: <span class="hljs-string">'segundo'</span>}
</code></pre>
<p>Perceba que os objetos <code>'um</code>' e <code>'primeiro'</code>estão separados por dois pontos (<code>:</code>). É assim que se formam os dicionários: para o objeto <code>'um'</code>é atribuído outro objeto, o <code>'primeiro'</code>, e assim sucessivamente. Para localizarmos um objeto dentro de uma lista, o procedimento é parecido com a lista:</p>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python">ordem[<span class="hljs-string">'um'</span>]
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code class="lang-python"><span class="hljs-string">'primeiro'</span>
</code></pre>
<hr />
<p>Nesta aula, foram apresentados alguns elementos essenciais na linguagem Python que você precisará ter em mente ao programar. Continuaremos a introdução em um próximo post da série, onde será mostrado um conteúdo referente a funções.</p>
<p>Até a próxima aula e, caso queira, já vá deixando um feedback! 😁</p>
<hr />
<h2 id="notas">NOTAS:</h2>
<p>(<strong>NOTA 1</strong>: Na linguagem Python, é permitido fazer comentários dentro de linhas de código. Para tanto, basta adicionar o sinal <code>#</code> antes de escrever. Tais comentários não serão consideradas pelo programa interpretador ao ler o código.)</p>
<p>(<strong>NOTA 2</strong>: Como foi mencionado antes, em vez de ser um símbolo de porcentagem, em Python o símbolo <code>%</code> representa uma operação aritmética distinta, o <a target="_blank" href="https://www.freecodecamp.org/news/the-python-modulo-operator-what-does-the-symbol-mean-in-python-solved/"><strong>módulo</strong></a>. Basicamente, o módulo representa <strong>o resto de uma divisão</strong>.
Exemplo: no caso acima, quando chamada a linha <code>13 % 5</code>, estamos efetuando a divisão de <code>13</code> por <code>5</code>; o quociente dessa divisão é <code>5</code>, enquanto que o resto (que é o que aparece no output) é <code>3</code>. Você pode ver mais sobre isso clicando <a target="_blank" href="http://excript.com/python/modulo-da-divisao-python.html">aqui</a> e <a target="_blank" href="https://www.learnpython.org/pt/Operadores_b%C3%A1sicos">aqui</a>)</p>
<hr />
<h2 id="para-ler-mais"><strong>Para ler mais:</strong></h2>
<ul>
<li><a target="_blank" href="https://docs.python.org/pt-br/3/tutorial/introduction.html#using-python-as-a-calculator">Documentação do Python - Usando o Python como uma calculadora</a></li>
<li><a target="_blank" href="https://www.devmedia.com.br/colecoes-no-python-listas-tuplas-e-dicionarios/40678">Criando coleções - DevMedia</a></li>
<li><a target="_blank" href="https://docs.python.org/pt-br/3/tutorial/datastructures.html">Documentação do Python - Estruturas de dados</a></li>
<li><a target="_blank" href="https://geo-python-site.readthedocs.io/en/latest/notebooks/L2/Python-basic-elements.html">Basic elements of Python - GeoPython</a></li>
<li><a target="_blank" href="https://users.astro.ufl.edu/~warner/prog/python.html">Python Basics - Astro Users</a></li>
</ul>
<h2 id="literatura-recomendada"><strong>Literatura recomendada</strong></h2>
<ul>
<li><em>Basic Core Python Programming</em>, de Meenu Kohli (<a target="_blank" href="http://libgen.rs/book/index.php?md5=CDE2BCEA2E13C41D0D9CC160BF9E3C4B">Library Genesis</a>)</li>
<li><em>Coding Python</em>, de Michael e Eric Scratch</li>
<li><em>Curso Intensivo de Python</em>, de Eric Matthes (<a target="_blank" href="http://libgen.rs/book/index.php?md5=1C13103D7B9B54DDD8EFAC70ACA10DA1">Library Genesis</a>)</li>
<li><em>Data Science do Zero: Primeiras Regras com Python</em>, de Joel Grus (<a target="_blank" href="http://libgen.rs/book/index.php?md5=EE6D1DFB6DDF4F53391557E3E0C97000">Library Genesis</a>)</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Aula 1 - Sua Excelência, o Python]]></title><description><![CDATA[Antes de começarmos a ver linhas e blocos de código para fazer a análise e visualização de dados propriamente dita, é essencial ir esclarecendo alguns pontos e apresentando conceitos importantes, como a linguagem em si. Então, senhoras e senhores, a ...]]></description><link>https://blog.matheusyuri.pro/aula-1-sua-excelencia-o-python</link><guid isPermaLink="true">https://blog.matheusyuri.pro/aula-1-sua-excelencia-o-python</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[data structures]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Tue, 03 Aug 2021 18:07:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628011699211/UoEPtSGb6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Antes de começarmos a ver linhas e blocos de código para fazer a análise e visualização de dados propriamente dita, é essencial ir esclarecendo alguns pontos e apresentando conceitos importantes, como a linguagem em si. Então, senhoras e senhores, a partir de agora lhes apresento Sua Excelência, a linguagem Python!</p>
<p>Nesta aula, veremos:</p>
<ul>
<li>O que é a linguagem Python e por que utilizá-la ao analisar e visualizar dados;</li>
<li>Esclarecer os conceitos de <em>codificação</em> e <em>programação</em>;</li>
<li>Entender como escrever os primeiros códigos de Python, seja em linhas de código ou blocos.</li>
</ul>
<h2 id="o-que-e-o-python-afinal">O que é o Python, afinal?</h2>
<p>O Python é uma linguagem de programação que possui um propósito geral; isso significa que sua concepção se apoia no intuito de atender um grande número de áreas. No caso da análise de dados, o Python é utilizado em boa parte das aplicações, por sua rápida e fácil capacidade de desenvolvimento e processamento. </p>
<p>Há grandes vantagens de usar o Python, nos quais se incluem:</p>
<ul>
<li>O Python é <strong>gratuito</strong>: ao contrário de muitos <em>softwares</em> de análise de dados que existem por aí, não é necessário a aquisição de licenças ou pagamento de mensalidades para usar o Python. Ele é gratuito, e sempre será.</li>
<li>Ele é de <strong>código aberto</strong>: isso significa que você pode fazer cópias, modificações e reutilizações do Python sem nenhuma preocupação. Esse é um fato importante, pois o uso do Python se torna ilimitado. Você pode criar bibliotecas, algoritmos, e outras aplicações no Python livremente.</li>
<li>O Python está <strong>disponível nos principais sistemas operacionais</strong>: não importa se você usa Windows, Linux ou Mac para fazer suas atividades, o Python estará lá, de diversas formas. Inclusive, projetos como o Google Colaboratory permitem que você use Python tendo apenas acesso à Internet e um navegador.</li>
<li><strong>Uma imensa comunidade de desenvolvedores, cientistas de dados e, esperamos a partir de agora, ecólogos usam o Python</strong>. Às vezes, você pode se sentir perdido quando for usar o Python, o que é normal. O importante aqui é que, se for buscar respostas para suas dúvidas, quase certamente as achará, pois alguém da comunidade Python também passou pelas mesmas dificuldades. Plataformas como Kaggle e Stack Overflow são ótimos lugares para encontrar respostas para aquilo que você ainda tem dúvida.</li>
<li>O Python possui <strong>um riquíssimo ecossistema de pacotes/bibliotecas criadas por terceiros</strong>: Pesquisadores e desenvolvedores de todos os cantos do mundo desenvolvem diariamente pacotes de códigos em Python para atender as necessidades de várias áreas do conhecimento (a Ecologia, como será visto nas próximas aulas, está entre essas áreas.)</li>
</ul>
<h2 id="o-que-e-programacao-o-que-e-codificacao">O que é programação? O que é codificação?</h2>
<p>Antes de começarmos a ver as primeiras linhas de código em Python para analisar seus dados, é importante esclarecer dois conceitos: o de <strong>programação</strong> e <strong>codificação</strong>. Estes termos, apesar de comumente virem juntos, <strong>não significam a mesma coisa</strong>; 'programar' e 'codificar', portanto, não deveriam ser utilizadas de forma intercalada, como se fossem sinônimos.</p>
<p>Então, o que significam esses dois termos?</p>
<p>Programação é o ato de escrever <em>"programas"</em> que um computador possa executar e produzir alguns (úteis, na maioria das vezes) resultados. <a target="_blank" href="https://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_de_computadores">Esse é um processo que envolve vários passos</a>, como:</p>
<ol>
<li>Identificar aspectos do mundo real que podem ser resolvidos computacionalmente;</li>
<li>Identificar uma solução computacional para esses aspectos, focando sempre no que for melhor (mais rápido, mais fácil, mais abrangente possível);</li>
<li>Implementar essa solução em uma linguagem de computação específica;</li>
<li>Testar, validar, e ajustar essa solução implementada de forma frequente.</li>
</ol>
<p>A codificação é uma parte do processo geral de programação, mais especificamente o terceiro passo: <em>"Implementar a solução em uma linguagem de computação específica"</em>. Isso significa, portanto, fazer um processo de transcrição da solução para uma linguagem que possa ser interpretada por um computador. Seria o mesmo que o processo de escrever um texto em um determinado idioma, ou até mesmo escrever uma função matemática; nessas situações, você transfere algo que você pensou/imaginou para o papel ou para uma tela de uma maneira que outros entes (pessoas ou computadores) possam interpretar a mensagem e, quando necessário, fazer mais abstrações sobre ela. </p>
<p>É muito importante notar que, quando falamos na <em>"melhor"</em> solução computacional, temos sempre de considerar fatores muito além do computador. Aspectos como quem usará o programa, quais recursos (sejam financeiros ou mão-de-obra) o projeto possui e, sobretudo, a quantidade de tempo necessária há para formatar tal solução e assim poder extrair o melhor dela.</p>
<p>Agora, que você já tem ideia do que é o Python, e alguns pontos foram esclarecidos, podemos começar a ver como funciona a linguagem.</p>
<h2 id="primeiras-linhas-em-python-para-comecar-a-entender">Primeiras linhas em Python para começar a entender</h2>
<p>O Python é uma linguagem interpretada, que pode ser usada de duas principais maneiras:</p>
<ul>
<li><p>De forma interativa: quando você usa o Python como se fosse uma "calculadora científica", executando um comando de cada vez. Aqui entra os arquivos <code>.ipynb</code>, os chamados <strong>notebooks</strong>, com os quais trabalharemos na série.</p>
<p>Um exemplo simples disso é fazer uma operação matemática:</p>
<p><strong>Python</strong>:</p>
<pre><code class="lang-python"><span class="hljs-number">2</span>+<span class="hljs-number">2</span>
</code></pre>
<p><strong>Output</strong>: </p>
<pre><code class="lang-python"><span class="hljs-number">4</span>
</code></pre>
<p>Também podemos utilizar como exemplo o caso da função <code>print()</code></p>
<p><strong>Python</strong>: </p>
<pre><code class="lang-python">print(<span class="hljs-string">'Hello world!'</span>)
</code></pre>
<p><strong>Output</strong>: </p>
<pre><code class="lang-python">Hello world!
</code></pre>
<p><strong>Para entender melhor</strong>: abra um novo notebook no Google Colab e repita as linhas indicadas como <strong>Python</strong> acima. Observe os resultados.</p>
</li>
<li><p>Em forma de script: quando você vai executar uma série de comandos salvos num arquivo de texto. Usualmente, tais arquivos vêm em extensão <code>.py</code>. </p>
<ul>
<li>Exemplo: imagine que você tenha escrito em um ambiente do Anaconda um comando <code>print('Hello, world!')</code>e o tenha salvo num arquivo <code>meu_script.py</code>. Uma vez que você execute esse arquivo em um console Python, o resultado será a execução do comando que está dentro do arquivo <code>.py</code>. Para fazer a edição do arquivo, você precisará de uma IDE, pois o console apenas faz a execução. </li>
</ul>
</li>
</ul>
<p>Para as aulas dessa série, como já vimos, usaremos o Jupyter Notebook, seja no Anaconda ou no Google Colab. Nessas plataformas, usaremos a maneira interativa, através de arquivos <code>.ipynb</code>, para aprendermos a mexer com códigos Python, uma vez que trabalharemos com uma ou mais linhas de código, através de blocos. </p>
<p>Exemplificando: toda vez que iniciamos um notebook, precisamos importar algumas bibliotecas para podermos analisar e visualizar dados. Nesse caso, podemos, em vez de executar uma linha de cada vez para importação, puxar todas as bibliotecas de uma só vez usando um bloco de código:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
<span class="hljs-keyword">import</span> geopandas <span class="hljs-keyword">as</span> gpd
<span class="hljs-keyword">import</span> seaborn <span class="hljs-keyword">as</span> sns
<span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt
</code></pre>
<p>Estes blocos de código podem comportar qualquer quantidade de linhas de código necessárias para performar uma ação em específico. Comumente o notebook é separado em vários blocos de código, obedecendo o princípio de execução de <a target="_blank" href="https://www.codecademy.com/articles/how-to-use-jupyter-notebooks">um (bloco de) código por vez</a>.</p>
<hr />
<p>Nesta primeira aula, apresentamos a linguagem Python de forma mais teórica e prosaica, com uma introdução prática muito breve. Nas próximas aulas, iniciaremos a parte prática da série, misturando a teoria com códigos para fazer suas primeiras análises em Python, e assim entrar de vez no mundo dos dados e da programação. </p>
<p>Para ir conhecendo mais do Python, aproveite para explorar as referências dos hyperlinks, da seção <strong>Para ler mais</strong>, e da literatura recomendada. É um material complementar que, a cada aula, proverá variadas visões e modos de explicar os assuntos abordados em cada post.</p>
<p>Espero que a série possa te beneficiar o máximo possível. Um grande abraço e até a próxima aula!</p>
<hr />
<p><strong>Para ler mais:</strong></p>
<ul>
<li><strong><a target="_blank" href="https://blog.back4app.com/pt/linguagens-de-codificacao/">As linguagens de codificação mais populares do mundo - Back4App</a></strong></li>
<li><strong><a target="_blank" href="https://medium.com/3xbit-academy/programação-e-codificação-73ea5f945224">Programação e Codificação. A diferença entre ambas definições - 3xbit Academy</a></strong></li>
<li><strong><a target="_blank" href="https://bytesdainformacao.blogspot.com/2014/08/programacao-vs-codificacao.html">Programação Vs. Codificação - Bytes da Informação</a></strong></li>
<li><strong><a target="_blank" href="https://engenhariadealgoritmo.blogspot.com/2009/07/programacao-x-codificacao.html?m=1">Programação x Codificação - Engenharia de Algoritmo, Desenvolvimento Tecnológico e Inovação</a></strong></li>
<li><strong><a target="_blank" href="https://www.akitaonrails.com/2014/05/02/off-topic-carreira-em-programacao-codificar-nao-e-programar">[Off-Topic] Carreira em Programação - Codificar não é Programar - AkitaOnRails.com</a></strong></li>
<li><strong><a target="_blank" href="https://www.freecodecamp.org/news/difference-between-coding-and-programming/#:~:text=Coding is a part of,and performs a certain task.&amp;text=Coding doesn't require as,translation to machine readable form.">What is the Difference Between Coding and Programming? - FreeCodeCamp</a></strong></li>
<li><strong><a target="_blank" href="https://www.upgrad.com/blog/coding-vs-programming/">Coding vs. Programming: A Never Ending Debate - upGrad</a></strong></li>
<li><strong><a target="_blank" href="https://www.goodcore.co.uk/blog/coding-vs-programming/">Coding Vs Programming For Beginners: What Is The Difference? - GoodCore</a></strong></li>
<li><strong><a target="_blank" href="https://www.thinkful.com/blog/coding-vs-programming/">Coding vs Programming - Thinkful</a></strong></li>
<li><strong><a target="_blank" href="https://www.python.org/doc/essays/blurb/">What is Python? Executive Summary - Python.org</a></strong></li>
<li><strong><a target="_blank" href="https://www.coursera.org/articles/what-is-python-used-for-a-beginners-guide-to-using-python">What Is Python Used For? A Beginner’s Guide - Coursera</a></strong></li>
<li><strong><a target="_blank" href="https://www.businessinsider.com/what-is-python">What Is Python? the Programming Language, Explained - BusinessInsider</a></strong></li>
<li><strong><a target="_blank" href="https://opensource.com/resources/python">What is Python? - Opensource.com</a></strong></li>
<li><strong><a target="_blank" href="https://www.futurelearn.com/info/blog/what-is-python-used-for">What is Python used for? | 10 practical Python uses - FutureLearn</a></strong></li>
<li><strong><a target="_blank" href="https://www.w3schools.com/python/python_intro.asp">Introduction to Python -  w3Schools</a></strong></li>
</ul>
<p><strong>Literatura recomendada:</strong></p>
<ul>
<li><em>Pense em Python</em>, de Allen B. Downey (<a target="_blank" href="http://libgen.rs/book/index.php?md5=E13D26C0FD0D61CFE1884ECF25EB2123">Library Genesis</a>)</li>
<li><em>Learn to Program with Python 3: A Step-by-Step Guide to Programming</em>, de Irv Kalb (<a target="_blank" href="http://libgen.rs/book/index.php?md5=55896AF2DBCBED4A3FB213A69AD32FA8">Library Genesis</a>)</li>
<li><em>Beginning Programming with Python (Série For Dummies)</em>, de John Paul Mueller (<a target="_blank" href="http://libgen.rs/book/index.php?md5=EC69AA1535CD82C735EE14ABFC05048F">Library Genesis</a>)</li>
<li><em>Starting out with Python</em>, de Tony Gaddis (<a target="_blank" href="http://libgen.rs/book/index.php?md5=06B801B0E93779722671CCBAE8101DCC">Library Genesis</a>)</li>
<li><em>Learn Python Visually</em>, de Tristan Bunn (<a target="_blank" href="http://libgen.rs/book/index.php?md5=06D0EAF6D35299021DBBA5909B318AE0">Library Genesis</a>)</li>
<li><em>Python Basics: A Practical Introduction to Python 3</em>, de Fetcher Heisler, David Amos, Dan Bader, e Joanna Jablonski, do site Real Python (<a target="_blank" href="http://libgen.rs/book/index.php?md5=06D0EAF6D35299021DBBA5909B318AE0">Library Genesis</a>)</li>
<li><em>Beyond the Basic Stuff with Python</em>, de Al Sweigart (<a target="_blank" href="http://libgen.rs/book/index.php?md5=AB52FE24E511E29BE73786864EBE0410">Library Genesis</a>)</li>
<li><em>Python in a Nutshell: A Desktop Quick Reference</em>, de Alex Martelli, Anna Ravenscroft, e Steve Holden (<a target="_blank" href="http://libgen.rs/book/index.php?md5=79BF433833EC537BA7594B43DC0B09CB">Library Genesis</a>)</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Aula 0.2 - O que você precisa saber (e instalar) para começar]]></title><description><![CDATA[O que você precisará para acompanhar a série?
Nessa série de posts, como já foi escrito, utilizaremos a linguagem Python para analisar dados. Uma vantagem de se utilizar o Python para analisar dados é a sua faciliade de acesso: para usá-lo, em um pri...]]></description><link>https://blog.matheusyuri.pro/aula-02-o-que-voce-precisa-saber-e-instalar-para-comecar</link><guid isPermaLink="true">https://blog.matheusyuri.pro/aula-02-o-que-voce-precisa-saber-e-instalar-para-comecar</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[Data Science]]></category><dc:creator><![CDATA[Matheus Halmenschlager]]></dc:creator><pubDate>Tue, 20 Jul 2021 12:11:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1626782422020/6G7LfmGiX.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="o-que-voce-precisara-para-acompanhar-a-serie">O que você precisará para acompanhar a série?</h1>
<p>Nessa série de posts, como já foi escrito, utilizaremos a linguagem Python para analisar dados. Uma vantagem de se utilizar o Python para analisar dados é a sua faciliade de acesso: para usá-lo, em um primeiro momento, é necessário apenas <strong>um computador com acesso à Internet</strong>. A razão para tanto é simples: na rede mundial estão disponíveis os chamados 'notebook interfaces' (uma explicação do que se trata isso <a target="_blank" href="https://en.wikipedia.org/wiki/Notebook_interface">está aqui, em inglês</a>. </p>
<h2 id="google-colaboratory-para-trabalhar-na-web">Google Colaboratory para trabalhar na web</h2>
<p>Nessa série, em específico, concentrarei as aulas e desafios na ferramenta <a target="_blank" href="https://research.google.com/colaboratory/">Google Colaboratory</a>. Ela é baseada no <a target="_blank" href="https://jupyter.org/">Jupyter Notebook</a> e permite fazer uma mescla de anotações e códigos em um só local, <strong>usando a computação em nuvem da Google para isso</strong>. Portanto, quem não possui uma máquina capaz de fazer um processamento de dados mais robusto, poderá usar o Google Colab livremente para a série, sem precisar fazer download de nenhum <em>software</em> ou <em>dataset</em>. A única coisa que você precisará fazer, se ainda não tiver, é <strong>criar uma conta Google</strong> para poder acompanhar o conteúdo. O vídeo a seguir relata um pouco do que se trata o Google Colab, e como você pode utilizá-lo para fazer suas análises em Python:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/_YVDfI6FIo8"></iframe>

<p>(<strong>Só um detalhe:</strong> Se for usar a ferramenta Google Colab, você provavelmente não precisará instalar nenhuma biblioteca, pois a Google fornece um ambiente com as principais ferramentas de análises instaladas. Em vários tutoriais, inclusive na série original que está sendo base para essa, há orientações de como instalar bibliotecas no Python, mas em algum post próximo escreverei sobre o procedimento.)</p>
<h2 id="instalando-o-pacote-anaconda-para-trabalhar-localmenteoff-line">Instalando o pacote Anaconda para trabalhar localmente/off-line</h2>
<p>No caso de você querer trabalhar localmente ou off-line com os notebooks, você pode instalar o <a target="_blank" href="https://www.anaconda.com/products/individual"><strong>pacote Anaconda</strong></a>. No caso, você precisará instalar o Anaconda versão Python 3, onde você poderá acessar o Jupyter Notebook. Aqui vai uma sugestão de vídeo com um tutorial para instalação do Jupyter através do Anaconda:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/_eK0z5QbpKA"></iframe>

<p>(<strong>Outro detalhe:</strong> Aqui, diferente de quando se vai trabalhar com o Google Colab, é necessário que você instale as bibliotecas que irá utilizar antes de começar a fazer qualquer coisa. Como já foi escrito, num próximo post estarei explicando como fazer isso em pacotes como o Anaconda e no Jupyter Notebook.)</p>
<h2 id="acessando-o-repositorio-no-github">Acessando o repositório no GitHub</h2>
<p>O <a target="_blank" href="https://github.com">GitHub</a>, para quem não conhece, é como uma rede social, mas voltada ao compartilhamento de códigos, softwares e outros notebooks. É nele que se encontrará o <a target="_blank" href="https://github.com/mhalmenschlager/python-biologia">repositório de notebooks que serão criados e utilizados para a série</a>, além dos dados que utilizaremos nas aulas. Você não precisa necessariamente criar uma conta no GitHub, mas é interessante dar uma olhada na plataforma, que pode lhe ajudar em projetos futuros. Ela é baseada no sistema Git de versionamento de arquivos, que é relativamente fácil de aprender. Uma breve explicação sobre o Git e o GitHub pode ser encontrada <a target="_blank" href="https://tableless.com.br/tudo-que-voce-queria-saber-sobre-git-e-github-mas-tinha-vergonha-de-perguntar/">aqui</a>.</p>
<h2 id="datasets"><em>Datasets</em></h2>
<p>Falando em dados, é importante saber que os <em>datasets</em> (ou seja, os conjuntos de dados) que utilizaremos nas aulas, estarão disponíveis na Internet, seja no repositório do GitHub, seja em outras fontes. No início de cada parte prática, os links para acessar os dados serão disponibilizados. A não ser que você queira trabalhar com os dados off-line, os <em>datasets</em> não precisarão ser salvos da máquina, uma vez que serão 'puxados' desses links. Instruções sobre como fazer isso, além de orientações sobre como é possível trabalhar off-line com o Python e os dados, aparecerão nas próximas aulas.</p>
<p>Uma vez conhecidos esses pontos, acredito que você estará pronto para começar a aprender como usar o Python para analisar seus dados. Quaisquer outras dúvidas, fique à vontade para questionar pelos canais de comunicação.</p>
<p>Um grande abraço e até a primeira aula!</p>
]]></content:encoded></item></channel></rss>