4.7 Transformações de Variáveis

Em Section 4.3.1, vimos que filter funciona pegando uma ou mais colunas de origem e filtrando-as por meio da aplicação de uma função de “filtragem.” Para recapitular, aqui está um exemplo de filtro usando a sintaxe source => f::Function: filter(:name => name -> name == "Alice", df).

Em Section 4.4, vimos que select pode pegar uma ou mais colunas de origem e colocá-las em uma ou mais colunas de destino source => target. Também para recapitular aqui está um exemplo: select(df, :name => :people_names).

Nesta seção, discutimos como transformar variáveis, ou seja, como modificar dados. Em DataFrames.jl, a sintaxe é source => transformation => target.

Como antes, usamos o dataset grades_2020:

function grades_2020()
    name = ["Sally", "Bob", "Alice", "Hank"]
    grade_2020 = [1, 5, 8.5, 4]
    DataFrame(; name, grade_2020)
end
grades_2020()
name grade_2020
Sally 1.0
Bob 5.0
Alice 8.5
Hank 4.0

Suponha que queremos aumentar todas as notas em grades_2020 por 1. Primeiro, definimos uma função que leva como argumento um vetor de dados e retorna todos os seus elementos acrescidos de 1. Depois usamos a função transform do DataFrames.jl que, como todas as funções nativas DataFrames.jl’, tem como primeiro argumento um DataFrame, seguido pela sintaxe de transformação:

plus_one(grades) = grades .+ 1
transform(grades_2020(), :grade_2020 => plus_one)
name grade_2020 grade_2020_plus_one
Sally 1.0 2.0
Bob 5.0 6.0
Alice 8.5 9.5
Hank 4.0 5.0

Aqui, a função plus_one recebe toda a coluna :grade_2020. Essa é a razão pela qual adicionamos o caractere de “ponto” do broadcasting . antes do operador +. Para uma recapitulação sobre broadcasting por gentileza veja Section 3.2.1.

Como dissemos acima, a minilinguagem do módulo DataFrames.jl é sempre source => transformation => target. Então, se quisermos manter a nomenclatura da coluna alvo (target) na coluna de output podemos fazer:

transform(grades_2020(), :grade_2020 => plus_one => :grade_2020)
name grade_2020
Sally 2.0
Bob 6.0
Alice 9.5
Hank 5.0

Também podemos usar o argumento de palavra-chave renamecols=false:

transform(grades_2020(), :grade_2020 => plus_one; renamecols=false)
name grade_2020
Sally 2.0
Bob 6.0
Alice 9.5
Hank 5.0

A mesma transformação também pode ser escrita com select:

select(grades_2020(), :, :grade_2020 => plus_one => :grade_2020)
name grade_2020
Sally 2.0
Bob 6.0
Alice 9.5
Hank 5.0

onde o : significa “selecione todas as colunas” como descrito em Section 4.4. Como alternativa, você também pode utilizar o broadcasting de Julia e modificar a coluna grade_2020 acessando-a com df.grade_2020:

df = grades_2020()
df.grade_2020 = plus_one.(df.grade_2020)
df
name grade_2020
Sally 2.0
Bob 6.0
Alice 9.5
Hank 5.0

Mas, embora o último exemplo seja mais fácil, pois se baseia em operações nativas de Julia, é altamente recomendável usar as funções fornecidas por DataFrames.jl na maioria dos casos porque são mais robustas e fáceis de trabalhar.

4.7.1 Transformações Múltiplas

Para mostrar como transformar duas colunas ao mesmo tempo, usamos os dados sobre os quais realizamos o left join em Section 4.6:

leftjoined = leftjoin(grades_2020(), grades_2021(); on=:name)
name grade_2020 grade_2021
Sally 1.0 9.5
Hank 4.0 6.0
Bob 5.0 missing
Alice 8.5 missing

Com isso, podemos adicionar uma coluna dizendo se alguém foi aprovado pelo critério de que todas as suas notas estivessem acima 5.5:

pass(A, B) = [5.5 < a || 5.5 < b for (a, b) in zip(A, B)]
transform(leftjoined, [:grade_2020, :grade_2021] => pass; renamecols=false)
name grade_2020 grade_2021 grade_2020_grade_2021
Sally 1.0 9.5 true
Hank 4.0 6.0 true
Bob 5.0 missing missing
Alice 8.5 missing true

Podemos limpar o resultado e colocar a lógica em uma função para obter uma lista de todos os alunos aprovados:

function only_pass()
    leftjoined = leftjoin(grades_2020(), grades_2021(); on=:name)
    pass(A, B) = [5.5 < a || 5.5 < b for (a, b) in zip(A, B)]
    leftjoined = transform(leftjoined, [:grade_2020, :grade_2021] => pass => :pass)
    passed = subset(leftjoined, :pass; skipmissing=true)
    return passed.name
end
only_pass()
["Sally", "Hank", "Alice"]


CC BY-NC-SA 4.0 Jose Storopoli, Rik Huijzer, Lazaro Alonso