import polars as pl
Desafio 11
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
- 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.
# 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)
= pl.read_csv(
df "renda_adulta.csv.gz",
=False,
has_header=colunas,
new_columns=tipos_colunas,
dtypes="?"
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 ┆ │
└─────┴──────────────┴────────┴────────────┴───┴──────────────┴─────────────┴─────────────┴────────┘
- 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})
- 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)
- Quantas pessoas recebem acima de $50.000 e quantas pessoas recebem abaixo deste limiar?
# Contagem de pessoas por categoria de renda
= df["income"].value_counts().sort("income")
contagem_renda print(contagem_renda)
shape: (2, 2)
┌────────┬───────┐
│ income ┆ count │
│ --- ┆ --- │
│ str ┆ u32 │
╞════════╪═══════╡
│ <=50K ┆ 24720 │
│ >50K ┆ 7841 │
└────────┴───────┘
- 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
= df.melt(
renda_longo =[
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
], =["capital-gain", "capital-loss"], # colunas que serão empilhadas
value_vars="tipo", # nova coluna indicando o tipo (gain ou loss)
variable_name="Valor" # nova coluna com os valores numéricos
value_name )
<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 │
└─────┴─────────────────┴────────┴────────────┴───┴────────────────┴────────┴──────────────┴───────┘
- 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 "income") # agrupa pelas classes de renda
df.group_by(
.agg("hours-per-week").mean().alias("media_horas")
pl.col(
)"income") # ordena para exibir <=50K primeiro
.sort(
)print(media_horas)
shape: (2, 2)
┌────────┬─────────────┐
│ income ┆ media_horas │
│ --- ┆ --- │
│ str ┆ f64 │
╞════════╪═════════════╡
│ <=50K ┆ 38.84021 │
│ >50K ┆ 45.473026 │
└────────┴─────────────┘
- Se cada linha representa uma pessoa, quantas pessoas foram amostradas em cada profissão?
= (
contagem_profissao "occupation") # Agrupa o DataFrame pela coluna 'occupation
df.group_by(len().alias("n_pessoas")) # Conta o número de linhas (pessoas) em cada grupo e nomeia a coluna como 'n_pessoas'
.agg(pl."occupation") # Ordena o resultado em ordem alfabética pelo nome da profissão
.sort(
)
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 │
└──────────────────┴───────────┘
- 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
"Agg")
matplotlib.use(import matplotlib.pyplot as plt # Importa a biblioteca Matplotlib para criação de gráficos
# Criação do gráfico de barras
"income"], media_horas["media_horas"], color=['skyblue', 'salmon'])
plt.bar(media_horas["Média de horas trabalhadas por classe salarial")
plt.title("Classe salarial")
plt.xlabel("Média de horas semanais")
plt.ylabel( plt.show()
- 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 "sex", "income"])
df.group_by(["quantidade"))
.agg(pl.count().alias(
.with_columns(["quantidade") / pl.col("quantidade").sum().over("sex") * 100)
(pl.col("percentual")
.alias(
])filter(pl.col("income") == ">50K")
."sex")
.sort( )
<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