Vários Problemas de Análise de Dados

Intermediate

This tutorial is from open-source community. Access the source code

Introdução

Neste laboratório, você aprenderá a trabalhar com vários contêineres de dados Python e a utilizar list comprehensions (compreensões de lista), set comprehensions (compreensões de conjunto) e dictionary comprehensions (compreensões de dicionário). Você também explorará o módulo collections, que fornece ferramentas úteis para o tratamento de dados.

Python oferece ferramentas poderosas para manipulação e análise de dados. Neste laboratório, você praticará o uso das estruturas de dados embutidas do Python e ferramentas especializadas para analisar diferentes conjuntos de dados. Começando com um conjunto de dados de portfólio simples, você progredirá para a análise de dados de ônibus da Chicago Transit Authority (CTA) para extrair insights significativos.

Este é um Lab Guiado, que fornece instruções passo a passo para ajudá-lo a aprender e praticar. Siga as instruções cuidadosamente para completar cada etapa e ganhar experiência prática. Dados históricos mostram que este é um laboratório de nível iniciante com uma taxa de conclusão de 82%. Recebeu uma taxa de avaliações positivas de 96% dos estudantes.

Trabalhando com Dicionários e Dados CSV

Vamos começar examinando um conjunto de dados simples sobre participações acionárias. Nesta etapa, você aprenderá como ler dados de um arquivo CSV e armazená-los em um formato estruturado usando dicionários.

Um arquivo CSV (Valores Separados por Vírgula) é uma maneira comum de armazenar dados tabulares, onde cada linha representa uma linha e os valores são separados por vírgulas. Dicionários em Python são uma estrutura de dados poderosa que permite armazenar pares chave-valor. Ao usar dicionários, podemos organizar os dados do arquivo CSV de uma maneira mais significativa.

Primeiro, crie um novo arquivo Python no WebIDE seguindo estas etapas:

  1. Clique no botão "New File" (Novo Arquivo) no WebIDE
  2. Nomeie o arquivo readport.py
  3. Copie e cole o seguinte código no arquivo:
## readport.py

import csv

## A function that reads a file into a list of dictionaries
def read_portfolio(filename):
    portfolio = []
    with open(filename) as f:
        rows = csv.reader(f)
        headers = next(rows)   ## Skip the header row
        for row in rows:
            record = {
                'name': row[0],
                'shares': int(row[1]),
                'price': float(row[2])
            }
            portfolio.append(record)
    return portfolio

Este código define uma função read_portfolio que realiza várias tarefas importantes:

  1. Ele abre um arquivo CSV especificado pelo parâmetro filename. A função open é usada para acessar o arquivo, e a instrução with garante que o arquivo seja fechado corretamente depois de terminarmos de lê-lo.
  2. Ele pula a linha do cabeçalho. A linha do cabeçalho geralmente contém os nomes das colunas no arquivo CSV. Usamos next(rows) para mover o iterador para a próxima linha, efetivamente pulando o cabeçalho.
  3. Para cada linha de dados, ele cria um dicionário. As chaves do dicionário são 'name', 'shares' e 'price'. Essas chaves nos ajudarão a acessar os dados de uma maneira mais intuitiva.
  4. Ele converte as ações em inteiros e os preços em números de ponto flutuante. Isso é importante porque os dados lidos do arquivo CSV estão inicialmente em formato de string, e precisamos de valores numéricos para cálculos.
  5. Ele adiciona cada dicionário a uma lista chamada portfolio. Esta lista conterá todos os registros do arquivo CSV.
  6. Finalmente, ele retorna a lista completa de dicionários.

Agora, vamos criar um arquivo para os dados de trânsito. Crie um novo arquivo chamado readrides.py com este conteúdo:

## readrides.py

import csv

def read_rides_as_dicts(filename):
    """
    Read the CTA bus data as a list of dictionaries
    """
    records = []
    with open(filename) as f:
        rows = csv.reader(f)
        headers = next(rows)   ## Skip header
        for row in rows:
            route = row[0]
            date = row[1]
            daytype = row[2]
            rides = int(row[3])
            record = {
                'route': route,
                'date': date,
                'daytype': daytype,
                'rides': rides
            }
            records.append(record)
    return records

Esta função read_rides_as_dicts funciona de maneira semelhante à função read_portfolio. Ela lê um arquivo CSV relacionado aos dados de ônibus da CTA, pula a linha do cabeçalho, cria um dicionário para cada linha de dados e armazena esses dicionários em uma lista.

Agora, vamos testar a função read_portfolio abrindo um terminal no WebIDE:

  1. Clique no menu "Terminal" e selecione "New Terminal" (Novo Terminal)
  2. Inicie o interpretador Python digitando python3
  3. Execute os seguintes comandos:
>>> from readport import read_portfolio
>>> portfolio = read_portfolio('/home/labex/project/portfolio.csv')
>>> from pprint import pprint
>>> pprint(portfolio)
[{'name': 'AA', 'price': 32.2, 'shares': 100},
 {'name': 'IBM', 'price': 91.1, 'shares': 50},
 {'name': 'CAT', 'price': 83.44, 'shares': 150},
 {'name': 'MSFT', 'price': 51.23, 'shares': 200},
 {'name': 'GE', 'price': 40.37, 'shares': 95},
 {'name': 'MSFT', 'price': 65.1, 'shares': 50},
 {'name': 'IBM', 'price': 70.44, 'shares': 100}]

A função pprint (pretty print - impressão formatada) é usada aqui para exibir os dados em um formato mais legível. Cada item na lista é um dicionário que representa uma participação acionária. O dicionário tem as seguintes chaves:

  • Um símbolo da ação (name): Esta é a abreviação usada para identificar a ação.
  • Número de ações possuídas (shares): Isso indica quantas ações da ação são mantidas.
  • Preço de compra por ação (price): Este é o preço pelo qual cada ação foi comprada.

Observe que algumas ações como 'MSFT' e 'IBM' aparecem várias vezes. Elas representam diferentes compras da mesma ação, que podem ter sido feitas em momentos e preços diferentes.

Usando List, Set e Dictionary Comprehensions

As Python comprehensions são uma maneira realmente útil e concisa de criar novas coleções com base nas existentes. Coleções em Python podem ser listas, conjuntos ou dicionários, que são como contêineres que armazenam diferentes tipos de dados. Comprehensions permitem que você filtre certos dados, transforme os dados de alguma forma e os organize de forma mais eficiente. Nesta parte, usaremos nossos dados de portfólio para explorar como essas comprehensions funcionam.

Primeiro, você precisa abrir um terminal Python, assim como fez na etapa anterior. Depois que o terminal estiver aberto, você inserirá os seguintes exemplos um por um. Essa abordagem prática o ajudará a entender como as comprehensions funcionam na prática.

List Comprehensions (Compreensões de Lista)

Uma list comprehension é uma sintaxe especial em Python que cria uma nova lista. Ele faz isso aplicando uma expressão a cada item em uma coleção existente.

Vamos começar com um exemplo. Primeiro, importaremos uma função para ler nossos dados de portfólio. Em seguida, usaremos a list comprehension para filtrar certas participações do portfólio.

>>> from readport import read_portfolio
>>> portfolio = read_portfolio('/home/labex/project/portfolio.csv')

## Find all holdings with more than 100 shares
>>> large_holdings = [s for s in portfolio if s['shares'] > 100]
>>> print(large_holdings)
[{'name': 'CAT', 'shares': 150, 'price': 83.44}, {'name': 'MSFT', 'shares': 200, 'price': 51.23}]

Neste código, primeiro importamos a função read_portfolio e a usamos para ler os dados do portfólio de um arquivo CSV. Em seguida, a list comprehension [s for s in portfolio if s['shares'] > 100] percorre cada item s na coleção portfolio. Ele inclui o item s na nova lista large_holdings somente se o número de ações nessa participação for maior que 100.

List comprehensions também podem ser usadas para realizar cálculos. Aqui estão alguns exemplos:

## Calculate the total cost of each holding (shares * price)
>>> holding_costs = [s['shares'] * s['price'] for s in portfolio]
>>> print(holding_costs)
[3220.0, 4555.0, 12516.0, 10246.0, 3835.15, 3255.0, 7044.0]

## Calculate the total cost of the entire portfolio
>>> total_portfolio_cost = sum([s['shares'] * s['price'] for s in portfolio])
>>> print(total_portfolio_cost)
44671.15

No primeiro exemplo, a list comprehension [s['shares'] * s['price'] for s in portfolio] calcula o custo total de cada participação multiplicando o número de ações pelo preço de cada item no portfolio. No segundo exemplo, usamos a função sum junto com a list comprehension para calcular o custo total de todo o portfólio.

Set Comprehensions (Compreensões de Conjunto)

Uma set comprehension é usada para criar um conjunto a partir de uma coleção existente. Um conjunto é uma coleção que contém apenas valores exclusivos.

Vamos ver como funciona com nossos dados de portfólio:

## Find all unique stock names
>>> unique_stocks = {s['name'] for s in portfolio}
>>> print(unique_stocks)
{'MSFT', 'IBM', 'AA', 'GE', 'CAT'}

Neste código, a set comprehension {s['name'] for s in portfolio} percorre cada item s no portfolio e adiciona o nome da ação (s['name']) ao conjunto unique_stocks. Como os conjuntos armazenam apenas valores exclusivos, acabamos com uma lista de todas as ações diferentes em nosso portfólio, sem quaisquer duplicatas.

Dictionary Comprehensions (Compreensões de Dicionário)

Uma dictionary comprehension cria um novo dicionário aplicando expressões para criar pares chave-valor.

Aqui está um exemplo de como usar uma dictionary comprehension para contar o número total de ações para cada ação em nosso portfólio:

## Create a dictionary to count total shares for each stock
>>> totals = {s['name']: 0 for s in portfolio}
>>> for s in portfolio:
...     totals[s['name']] += s['shares']
...
>>> print(totals)
{'AA': 100, 'IBM': 150, 'CAT': 150, 'MSFT': 250, 'GE': 95}

Na primeira linha, a dictionary comprehension {s['name']: 0 for s in portfolio} cria um dicionário onde cada nome de ação (s['name']) é uma chave, e o valor inicial para cada chave é 0. Em seguida, usamos um loop for para percorrer cada item no portfolio. Para cada item, adicionamos o número de ações (s['shares']) ao valor correspondente no dicionário totals.

Essas comprehensions são muito poderosas porque permitem que você transforme e analise dados com apenas algumas linhas de código. Elas são uma ótima ferramenta para ter em seu kit de ferramentas de programação Python.

Explorando o Módulo Collections

Em Python, os contêineres embutidos, como listas, dicionários e conjuntos, são muito úteis. No entanto, o módulo collections do Python vai um passo além, fornecendo tipos de dados de contêiner especializados que estendem a funcionalidade desses contêineres embutidos. Vamos dar uma olhada mais de perto em alguns desses tipos de dados úteis.

Você continuará trabalhando em seu terminal Python e acompanhará os exemplos abaixo.

Counter (Contador)

A classe Counter é uma subclasse do dicionário. Seu principal objetivo é contar objetos hashable (com hash). Ele oferece uma maneira conveniente de contar itens e suporta uma variedade de operações.

Primeiro, precisamos importar a classe Counter e uma função para ler um portfólio. Em seguida, leremos um portfólio de um arquivo CSV.

>>> from collections import Counter
>>> from readport import read_portfolio
>>> portfolio = read_portfolio('/home/labex/project/portfolio.csv')

Agora, criaremos um objeto Counter para contar o número de ações para cada ação por seu nome.

## Create a counter to count shares by stock name
>>> totals = Counter()
>>> for s in portfolio:
...     totals[s['name']] += s['shares']
...
>>> print(totals)
Counter({'MSFT': 250, 'IBM': 150, 'CAT': 150, 'AA': 100, 'GE': 95})

Uma das grandes características do objeto Counter é que ele inicializa automaticamente novas chaves com uma contagem de 0. Isso significa que você não precisa verificar se uma chave existe antes de incrementar sua contagem, o que simplifica o código para acumular contagens.

Os contadores também vêm com métodos especiais. Por exemplo, o método most_common() é muito útil para análise de dados.

## Get the two stocks with the most shares
>>> most_common_stocks = totals.most_common(2)
>>> print(most_common_stocks)
[('MSFT', 250), ('IBM', 150)]

Além disso, os contadores podem ser combinados usando operações aritméticas.

## Create another counter
>>> more = Counter()
>>> more['IBM'] = 75
>>> more['AA'] = 200
>>> more['ACME'] = 30
>>> print(more)
Counter({'AA': 200, 'IBM': 75, 'ACME': 30})

## Add two counters together
>>> combined = totals + more
>>> print(combined)
Counter({'AA': 300, 'MSFT': 250, 'IBM': 225, 'CAT': 150, 'GE': 95, 'ACME': 30})

defaultdict (defaultdict)

O defaultdict é semelhante a um dicionário normal, mas tem um recurso exclusivo. Ele fornece um valor padrão para chaves que ainda não existem. Isso pode simplificar seu código, pois você não precisa mais verificar se uma chave existe antes de usá-la.

>>> from collections import defaultdict

## Group portfolio entries by stock name
>>> byname = defaultdict(list)
>>> for s in portfolio:
...     byname[s['name']].append(s)
...
>>> print(byname['IBM'])
[{'name': 'IBM', 'shares': 50, 'price': 91.1}, {'name': 'IBM', 'shares': 100, 'price': 70.44}]
>>> print(byname['AA'])
[{'name': 'AA', 'shares': 100, 'price': 32.2}]

Quando você cria um defaultdict(list), ele cria automaticamente uma nova lista vazia para cada nova chave. Portanto, você pode anexar diretamente ao valor de uma chave, mesmo que a chave não existisse antes. Isso elimina a necessidade de verificar se a chave existe e criar uma lista vazia manualmente.

Você também pode usar outras funções de fábrica padrão. Por exemplo, você pode usar int, float ou até mesmo sua própria função personalizada.

## Use defaultdict with int to count items
>>> word_counts = defaultdict(int)
>>> words = ['apple', 'orange', 'banana', 'apple', 'orange', 'apple']
>>> for word in words:
...     word_counts[word] += 1
...
>>> print(word_counts)
defaultdict(<class 'int'>, {'apple': 3, 'orange': 2, 'banana': 1})

Esses tipos de contêiner especializados do módulo collections podem tornar seu código mais conciso e eficiente quando você estiver trabalhando com dados.

Desafio de Análise de Dados com Dados da Chicago Transit Authority

Agora que você praticou o trabalho com diferentes estruturas de dados Python e o módulo collections, é hora de colocar essas habilidades em uso em uma tarefa de análise de dados do mundo real. Neste experimento, analisaremos os dados de passageiros de ônibus da Chicago Transit Authority (CTA). Essa aplicação prática o ajudará a entender como usar o Python para extrair informações significativas de conjuntos de dados do mundo real.

Entendendo os Dados

Primeiro, vamos dar uma olhada nos dados de trânsito com os quais trabalharemos. Em seu terminal Python, você executará algum código para carregar os dados e entender sua estrutura básica.

>>> import readrides
>>> rows = readrides.read_rides_as_dicts('/home/labex/project/ctabus.csv')
>>> print(len(rows))
## This will show the number of records in the dataset

>>> ## Let's look at the first record to understand the structure
>>> import pprint
>>> pprint.pprint(rows[0])

A instrução import readrides importa um módulo personalizado que possui uma função para ler os dados do arquivo CSV. A função readrides.read_rides_as_dicts lê os dados do arquivo CSV especificado e converte cada linha em um dicionário. len(rows) nos dá o número total de registros no conjunto de dados. Ao imprimir o primeiro registro usando pprint.pprint(rows[0]), podemos ver a estrutura de cada registro claramente.

Os dados contêm registros diários de passageiros para diferentes rotas de ônibus. Cada registro inclui:

  • route: O número da rota do ônibus
  • date: A data no formato "AAAA-MM-DD"
  • daytype: "W" para dia de semana, "A" para sábado ou "U" para domingo/feriado
  • rides: O número de passageiros naquele dia

Tarefas de Análise

Vamos resolver cada uma das questões do desafio, uma por uma:

Questão 1: Quantas rotas de ônibus existem em Chicago?

Para responder a esta pergunta, precisamos encontrar todos os números de rota exclusivos no conjunto de dados. Usaremos uma set comprehension para esta tarefa.

>>> ## Get all unique route numbers using a set comprehension
>>> unique_routes = {row['route'] for row in rows}
>>> print(len(unique_routes))

Uma set comprehension é uma maneira concisa de criar um conjunto. Neste caso, iteramos sobre cada linha na lista rows e extraímos o valor route. Como um conjunto armazena apenas elementos exclusivos, acabamos com um conjunto de todos os números de rota exclusivos. Imprimir o comprimento deste conjunto nos dá o número total de rotas de ônibus exclusivas.

Também podemos ver quais são algumas dessas rotas:

>>> ## Print a few of the route numbers
>>> print(list(unique_routes)[:10])

Aqui, convertemos o conjunto de rotas exclusivas em uma lista e, em seguida, imprimimos os primeiros 10 elementos dessa lista.

Questão 2: Quantas pessoas andaram no ônibus número 22 em 2 de fevereiro de 2011?

Para esta pergunta, precisamos filtrar os dados para encontrar o registro específico que corresponde à rota e data fornecidas.

>>> ## Find rides on route 22 on February 2, 2011
>>> target_date = "2011-02-02"
>>> target_route = "22"
>>>
>>> for row in rows:
...     if row['route'] == target_route and row['date'] == target_date:
...         print(f"Rides on route {target_route} on {target_date}: {row['rides']}")
...         break

Primeiro, definimos as variáveis target_date e target_route. Em seguida, iteramos sobre cada linha na lista rows. Para cada linha, verificamos se a route e a date correspondem aos nossos valores de destino. Se uma correspondência for encontrada, imprimimos o número de viagens e saímos do loop, pois encontramos o registro que estamos procurando.

Você pode modificar isso para verificar qualquer rota em qualquer data, alterando as variáveis target_date e target_route.

Questão 3: Qual é o número total de viagens feitas em cada rota de ônibus?

Vamos usar um Counter para calcular o total de viagens por rota. Um Counter é uma subclasse de dicionário do módulo collections que é usado para contar objetos hashable.

>>> from collections import Counter
>>>
>>> ## Initialize a counter
>>> total_rides_by_route = Counter()
>>>
>>> ## Sum up rides for each route
>>> for row in rows:
...     total_rides_by_route[row['route']] += row['rides']
...
>>> ## View the top 5 routes by total ridership
>>> for route, rides in total_rides_by_route.most_common(5):
...     print(f"Route {route}: {rides:,} total rides")

Primeiro, importamos a classe Counter do módulo collections. Em seguida, inicializamos um contador vazio chamado total_rides_by_route. Ao iterarmos sobre cada linha na lista rows, adicionamos o número de viagens para cada rota ao contador. Finalmente, usamos o método most_common(5) para obter as 5 principais rotas com o maior número total de passageiros e imprimir os resultados.

Questão 4: Quais cinco rotas de ônibus tiveram o maior aumento de passageiros em dez anos, de 2001 a 2011?

Esta é uma tarefa mais complexa. Precisamos comparar o número de passageiros em 2001 com o de 2011 para cada rota.

>>> ## Create dictionaries to store total annual rides by route
>>> rides_2001 = Counter()
>>> rides_2011 = Counter()
>>>
>>> ## Collect data for each year
>>> for row in rows:
...     if row['date'].startswith('2001-'):
...         rides_2001[row['route']] += row['rides']
...     elif row['date'].startswith('2011-'):
...         rides_2011[row['route']] += row['rides']
...
>>> ## Calculate increases
>>> increases = {}
>>> for route in unique_routes:
...     if route in rides_2001 and route in rides_2011:
...         increase = rides_2011[route] - rides_2001[route]
...         increases[route] = increase
...
>>> ## Find the top 5 routes with the biggest increases
>>> import heapq
>>> top_5_increases = heapq.nlargest(5, increases.items(), key=lambda x: x[1])
>>>
>>> ## Display the results
>>> print("Top 5 routes with the greatest ridership increase from 2001 to 2011:")
>>> for route, increase in top_5_increases:
...     print(f"Route {route}: increased by {increase:,} rides")
...     print(f"  2001 rides: {rides_2001[route]:,}")
...     print(f"  2011 rides: {rides_2011[route]:,}")
...     print()

Primeiro, criamos dois objetos Counter, rides_2001 e rides_2011, para armazenar o total de viagens para cada rota em 2001 e 2011, respectivamente. Ao iterarmos sobre cada linha na lista rows, verificamos se a data começa com '2001-' ou '2011-' e adicionamos as viagens ao contador apropriado.

Em seguida, criamos um dicionário vazio increases para armazenar o aumento no número de passageiros para cada rota. Iteramos sobre as rotas exclusivas e calculamos o aumento subtraindo as viagens de 2001 das viagens de 2011 para cada rota.

Para encontrar as 5 principais rotas com os maiores aumentos, usamos a função heapq.nlargest. Essa função recebe o número de elementos a serem retornados (5 neste caso), o iterável (increases.items()) e uma função de chave (lambda x: x[1]) que especifica como comparar os elementos.

Finalmente, imprimimos os resultados, mostrando o número da rota, o aumento no número de passageiros e o número de viagens em 2001 e 2011.

Esta análise identifica quais rotas de ônibus tiveram o maior crescimento no número de passageiros ao longo da década, o que pode indicar mudanças nos padrões populacionais, melhorias no serviço ou outras tendências interessantes.

Você pode estender essas análises de várias maneiras. Por exemplo, você pode querer:

  • Analisar os padrões de passageiros por dia da semana
  • Encontrar rotas com queda no número de passageiros
  • Comparar as variações sazonais no número de passageiros

As técnicas que você aprendeu neste laboratório fornecem uma base sólida para esse tipo de exploração e análise de dados.

Resumo

Neste laboratório, você aprendeu várias técnicas importantes de manipulação de dados em Python. Isso inclui ler e processar dados CSV em dicionários, usar list, set e dictionary comprehensions (compreensões de lista, conjunto e dicionário) para transformação de dados e aproveitar tipos de contêiner especializados do módulo collections. Você também aplicou essas habilidades para realizar análises de dados significativas.

Essas técnicas são fundamentais para a análise de dados em Python e são valiosas em vários cenários do mundo real. A capacidade de processar, transformar e extrair insights de dados é crucial para programadores Python. Continue praticando com seus próprios conjuntos de dados para aprimorar sua experiência em análise de dados em Python.