Desafio 11

Author

Nicole de Barros Silva

Laboratório: Introdução ao Polars

Importação e Manipulação de Dados Utilizando Polars

Introdução

Polars é uma biblioteca de manipulação de dados em Rust que foi projetada para ser rápida e eficiente, especialmente quando se trata de lidar com grandes conjuntos de dados. A principal vantagem do Polars em comparação com outras bibliotecas de manipulação de dados, como o pandas, é sua capacidade de processar dados em paralelo, aproveitando múltiplos núcleos de CPU. Isso resulta em operações significativamente mais rápidas, permitindo que analistas e cientistas de dados realizem tarefas complexas de transformação e agregação em grandes volumes de dados com eficiência. Além disso, a API do Polars é inspirada na do pandas, o que facilita a transição para usuários que já estão familiarizados com o ecossistema de Python.

Na ciência de dados, a capacidade de manipular e analisar grandes quantidades de dados de forma rápida e eficiente é crucial para a extração de insights significativos. Polars é particularmente valioso em cenários onde o desempenho é uma preocupação, como em análises em tempo real ou no processamento de grandes fluxos de dados. Sua integração com outras bibliotecas populares, como NumPy e Matplotlib, e sua compatibilidade com arquivos em formatos como CSV e Parquet tornam o Polars uma ferramenta versátil para cientistas de dados que buscam otimizar suas operações e maximizar a eficiência de suas análises. Com a crescente demanda por soluções de dados escaláveis, o Polars se destaca como uma opção promissora no arsenal de ferramentas de ciência de dados.

Objetivos

Ao fim deste laboratório, você deverá:

Ser capaz de importar arquivos tabulares (CSV ou TSV) utilizando a biblioteca Polars. Organizar e transformar tabelas de dados. Compreender operações básicas de manipulação de dados, como seleção, filtragem e ordenação. Calcular estatísticas descritivas e agrupadas utilizando as funções disponíveis no Polars. Criar visualizações informativas usando plotnine. Conjunto de Dados O conjunto de dados “Renda Adulta” contém informações demográficas e econômicas de indivíduos, que são utilizadas para prever se um indivíduo ganha mais ou menos de $50.000 por ano.

Atividade

  1. Utilizando o arquivo renda_adulta.csv e sabendo que ele não possui cabeçalho, faça a importação do banco de dados utilizando os nomes das colunas conforme apresentado acima e na sequência ali indicada. No momento da importação do arquivo, você deve, também, indicar os tipos de cada uma das colunas. Utilize o fato de que o símbolo ? representa valores faltantes.
import polars as pl
# Nomes das colunas conforme a descrição do enunciado
colunas = [
    "age", "workclass", "fnlwgt", "education", "education-num",
    "marital-status", "occupation", "relationship", "race", "sex",
    "capital-gain", "capital-loss", "hours-per-week",
    "native-country", "income"
]

# Tipos de cada coluna
tipos_colunas = [
    pl.Int64, pl.Utf8, pl.Int64, pl.Utf8, pl.Int64,
    pl.Utf8, pl.Utf8, pl.Utf8, pl.Utf8, pl.Utf8,
    pl.Int64, pl.Int64, pl.Int64, pl.Utf8, pl.Utf8
]

# Leitura do arquivo (comprimido em .gz)
df = pl.read_csv(
    "renda_adulta.csv.gz",
    has_header=False,
    new_columns=colunas,
    dtypes=tipos_colunas,
    null_values="?"
)
<string>:3: DeprecationWarning: the argument `dtypes` for `read_csv` is deprecated. It was renamed to `schema_overrides` in version 0.20.31.
print(df)
shape: (32_561, 15)
┌─────┬──────────────┬────────┬────────────┬───┬──────────────┬─────────────┬─────────────┬────────┐
│ age ┆ workclass    ┆ fnlwgt ┆ education  ┆ … ┆ capital-loss ┆ hours-per-w ┆ native-coun ┆ income │
│ --- ┆ ---          ┆ ---    ┆ ---        ┆   ┆ ---          ┆ eek         ┆ try         ┆ ---    │
│ i64 ┆ str          ┆ i64    ┆ str        ┆   ┆ i64          ┆ ---         ┆ ---         ┆ str    │
│     ┆              ┆        ┆            ┆   ┆              ┆ i64         ┆ str         ┆        │
╞═════╪══════════════╪════════╪════════════╪═══╪══════════════╪═════════════╪═════════════╪════════╡
│ 39  ┆ State-gov    ┆ 77516  ┆ Bachelors  ┆ … ┆ 0            ┆ 40          ┆ United-Stat ┆ <=50K  │
│     ┆              ┆        ┆            ┆   ┆              ┆             ┆ es          ┆        │
│ 50  ┆ Self-emp-not ┆ 83311  ┆ Bachelors  ┆ … ┆ 0            ┆ 13          ┆ United-Stat ┆ <=50K  │
│     ┆ -inc         ┆        ┆            ┆   ┆              ┆             ┆ es          ┆        │
│ 38  ┆ Private      ┆ 215646 ┆ HS-grad    ┆ … ┆ 0            ┆ 40          ┆ United-Stat ┆ <=50K  │
│     ┆              ┆        ┆            ┆   ┆              ┆             ┆ es          ┆        │
│ 53  ┆ Private      ┆ 234721 ┆ 11th       ┆ … ┆ 0            ┆ 40          ┆ United-Stat ┆ <=50K  │
│     ┆              ┆        ┆            ┆   ┆              ┆             ┆ es          ┆        │
│ 28  ┆ Private      ┆ 338409 ┆ Bachelors  ┆ … ┆ 0            ┆ 40          ┆ Cuba        ┆ <=50K  │
│ …   ┆ …            ┆ …      ┆ …          ┆ … ┆ …            ┆ …           ┆ …           ┆ …      │
│ 27  ┆ Private      ┆ 257302 ┆ Assoc-acdm ┆ … ┆ 0            ┆ 38          ┆ United-Stat ┆ <=50K  │
│     ┆              ┆        ┆            ┆   ┆              ┆             ┆ es          ┆        │
│ 40  ┆ Private      ┆ 154374 ┆ HS-grad    ┆ … ┆ 0            ┆ 40          ┆ United-Stat ┆ >50K   │
│     ┆              ┆        ┆            ┆   ┆              ┆             ┆ es          ┆        │
│ 58  ┆ Private      ┆ 151910 ┆ HS-grad    ┆ … ┆ 0            ┆ 40          ┆ United-Stat ┆ <=50K  │
│     ┆              ┆        ┆            ┆   ┆              ┆             ┆ es          ┆        │
│ 22  ┆ Private      ┆ 201490 ┆ HS-grad    ┆ … ┆ 0            ┆ 20          ┆ United-Stat ┆ <=50K  │
│     ┆              ┆        ┆            ┆   ┆              ┆             ┆ es          ┆        │
│ 52  ┆ Self-emp-inc ┆ 287927 ┆ HS-grad    ┆ … ┆ 0            ┆ 40          ┆ United-Stat ┆ >50K   │
│     ┆              ┆        ┆            ┆   ┆              ┆             ┆ es          ┆        │
└─────┴──────────────┴────────┴────────────┴───┴──────────────┴─────────────┴─────────────┴────────┘
  1. Apresente os tipos de cada uma das coluna.
print(df.schema)  # Exibe o esquema do DataFrame 'df', mostrando o nome e o tipo de dado de cada coluna
Schema({'age': Int64, 'workclass': String, 'fnlwgt': Int64, 'education': String, 'education-num': Int64, 'marital-status': String, 'occupation': String, 'relationship': String, 'race': String, 'sex': String, 'capital-gain': Int64, 'capital-loss': Int64, 'hours-per-week': Int64, 'native-country': String, 'income': String})
  1. Apresente as dimensões da tabela de dados.
print(df.shape) # Mostra o formato do DataFrame 'df', ou seja, uma tupla com (número de linhas, número de colunas)
(32561, 15)
  1. Quantas pessoas recebem acima de $50.000 e quantas pessoas recebem abaixo deste limiar?
# Contagem de pessoas por categoria de renda
contagem_renda = df["income"].value_counts().sort("income")
print(contagem_renda)
shape: (2, 2)
┌────────┬───────┐
│ income ┆ count │
│ ---    ┆ ---   │
│ str    ┆ u32   │
╞════════╪═══════╡
│ <=50K  ┆ 24720 │
│ >50K   ┆ 7841  │
└────────┴───────┘
  1. Crie um objeto chamado renda_longo, no qual você transforma as colunas capital-gain e capital-loss (formato wide) para formato longo. Os valores destas variáveis devem ser armazenados numa nova coluna chamada Valor e os tipos de valores (gain e loss) devem ser armazenados numa coluna chamada tipo.
# Transformar de formato wide para formato long
renda_longo = df.melt(
    id_vars=[
        "age", "workclass", "fnlwgt", "education", "education-num",
        "marital-status", "occupation", "relationship", "race",
        "sex", "hours-per-week", "native-country", "income"
    ],                         # colunas que permanecerão fixas
    value_vars=["capital-gain", "capital-loss"],  # colunas que serão empilhadas
    variable_name="tipo",       # nova coluna indicando o tipo (gain ou loss)
    value_name="Valor"          # nova coluna com os valores numéricos
)
<string>:2: DeprecationWarning: `DataFrame.melt` is deprecated; use `DataFrame.unpivot` instead, with `index` instead of `id_vars` and `on` instead of `value_vars`
print(renda_longo)
shape: (65_122, 15)
┌─────┬─────────────────┬────────┬────────────┬───┬────────────────┬────────┬──────────────┬───────┐
│ age ┆ workclass       ┆ fnlwgt ┆ education  ┆ … ┆ native-country ┆ income ┆ tipo         ┆ Valor │
│ --- ┆ ---             ┆ ---    ┆ ---        ┆   ┆ ---            ┆ ---    ┆ ---          ┆ ---   │
│ i64 ┆ str             ┆ i64    ┆ str        ┆   ┆ str            ┆ str    ┆ str          ┆ i64   │
╞═════╪═════════════════╪════════╪════════════╪═══╪════════════════╪════════╪══════════════╪═══════╡
│ 39  ┆ State-gov       ┆ 77516  ┆ Bachelors  ┆ … ┆ United-States  ┆ <=50K  ┆ capital-gain ┆ 2174  │
│ 50  ┆ Self-emp-not-in ┆ 83311  ┆ Bachelors  ┆ … ┆ United-States  ┆ <=50K  ┆ capital-gain ┆ 0     │
│     ┆ c               ┆        ┆            ┆   ┆                ┆        ┆              ┆       │
│ 38  ┆ Private         ┆ 215646 ┆ HS-grad    ┆ … ┆ United-States  ┆ <=50K  ┆ capital-gain ┆ 0     │
│ 53  ┆ Private         ┆ 234721 ┆ 11th       ┆ … ┆ United-States  ┆ <=50K  ┆ capital-gain ┆ 0     │
│ 28  ┆ Private         ┆ 338409 ┆ Bachelors  ┆ … ┆ Cuba           ┆ <=50K  ┆ capital-gain ┆ 0     │
│ …   ┆ …               ┆ …      ┆ …          ┆ … ┆ …              ┆ …      ┆ …            ┆ …     │
│ 27  ┆ Private         ┆ 257302 ┆ Assoc-acdm ┆ … ┆ United-States  ┆ <=50K  ┆ capital-loss ┆ 0     │
│ 40  ┆ Private         ┆ 154374 ┆ HS-grad    ┆ … ┆ United-States  ┆ >50K   ┆ capital-loss ┆ 0     │
│ 58  ┆ Private         ┆ 151910 ┆ HS-grad    ┆ … ┆ United-States  ┆ <=50K  ┆ capital-loss ┆ 0     │
│ 22  ┆ Private         ┆ 201490 ┆ HS-grad    ┆ … ┆ United-States  ┆ <=50K  ┆ capital-loss ┆ 0     │
│ 52  ┆ Self-emp-inc    ┆ 287927 ┆ HS-grad    ┆ … ┆ United-States  ┆ >50K   ┆ capital-loss ┆ 0     │
└─────┴─────────────────┴────────┴────────────┴───┴────────────────┴────────┴──────────────┴───────┘
  1. Quais são as médias de horas trabalhadas por classe salarial?
# Cálculo da média de horas semanais por classe salarial
media_horas = (
    df.group_by("income")  # agrupa pelas classes de renda
      .agg(
          pl.col("hours-per-week").mean().alias("media_horas")
      )
      .sort("income")     # ordena para exibir <=50K primeiro
)
print(media_horas)
shape: (2, 2)
┌────────┬─────────────┐
│ income ┆ media_horas │
│ ---    ┆ ---         │
│ str    ┆ f64         │
╞════════╪═════════════╡
│ <=50K  ┆ 38.84021    │
│ >50K   ┆ 45.473026   │
└────────┴─────────────┘
  1. Se cada linha representa uma pessoa, quantas pessoas foram amostradas em cada profissão?
contagem_profissao = (
    df.group_by("occupation") # Agrupa o DataFrame pela coluna 'occupation
      .agg(pl.len().alias("n_pessoas")) # Conta o número de linhas (pessoas) em cada grupo e nomeia a coluna como 'n_pessoas'
      .sort("occupation") # Ordena o resultado em ordem alfabética pelo nome da profissão
)

print(contagem_profissao)
shape: (15, 2)
┌──────────────────┬───────────┐
│ occupation       ┆ n_pessoas │
│ ---              ┆ ---       │
│ str              ┆ u32       │
╞══════════════════╪═══════════╡
│ null             ┆ 1843      │
│ Adm-clerical     ┆ 3770      │
│ Armed-Forces     ┆ 9         │
│ Craft-repair     ┆ 4099      │
│ Exec-managerial  ┆ 4066      │
│ …                ┆ …         │
│ Prof-specialty   ┆ 4140      │
│ Protective-serv  ┆ 649       │
│ Sales            ┆ 3650      │
│ Tech-support     ┆ 928       │
│ Transport-moving ┆ 1597      │
└──────────────────┴───────────┘
  1. Crie um gráfico de barras que apresente o número médio de horas trabalhadas semanalmente em função do nível salarial.
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt # Importa a biblioteca Matplotlib para criação de gráficos
# Criação do gráfico de barras
plt.bar(media_horas["income"], media_horas["media_horas"], color=['skyblue', 'salmon'])
plt.title("Média de horas trabalhadas por classe salarial")
plt.xlabel("Classe salarial")
plt.ylabel("Média de horas semanais")
plt.show()

  1. Desafio: existe alguma evidência de discriminação salarial entre gêneros biológicos?
# Proporção de pessoas que ganham >50K por gênero
proporcao_altos_salarios = (
    df.group_by(["sex", "income"])
      .agg(pl.count().alias("quantidade"))
      .with_columns([
          (pl.col("quantidade") / pl.col("quantidade").sum().over("sex") * 100)
          .alias("percentual")
      ])
      .filter(pl.col("income") == ">50K")
      .sort("sex")
)
<string>:4: DeprecationWarning: `pl.count()` is deprecated. Please use `pl.len()` instead.
(Deprecated in version 0.20.5)
print(proporcao_altos_salarios)  # Exibe a tabela final criada, com a quantidade e percentual de pessoas que ganham >50K por gênero biológico
shape: (2, 4)
┌────────┬────────┬────────────┬────────────┐
│ sex    ┆ income ┆ quantidade ┆ percentual │
│ ---    ┆ ---    ┆ ---        ┆ ---        │
│ str    ┆ str    ┆ u32        ┆ f64        │
╞════════╪════════╪════════════╪════════════╡
│ Female ┆ >50K   ┆ 1179       ┆ 10.946059  │
│ Male   ┆ >50K   ┆ 6662       ┆ 30.573658  │
└────────┴────────┴────────────┴────────────┘

Há evidência de desigualdade salarial entre gêneros no dataset, visto que a proporção de pessoas do sexo masculino que recebem mais de $50.000 por ano é significativamente maior do que a do sexo feminino. Embora a análise não prove discriminação diretamente (visto que pode haver outros fatores correlacionados), ela indica certa disparidade de renda entre os gêneros biológicos.

# Registra quando o html foi gerado
cat(paste0("Este HTML foi gerado em: ", Sys.time()))
Este HTML foi gerado em: 2025-10-07 11:39:30.636396