3 Tipos de Valores e Atributos
3.1 Introdução
Como vimos no capítulo passado, tudo que existe no R é um objeto. Eles são compostos de valores/dados e (potencialmente) atributos/metadados.
Haverão dois aprendizados principais: (i) temos duas famílias de tipos, todos os valores “do dia-a-dia” são vetores, e o resto são os poucos tipos internos do R; (ii) a diferença entre vetores atômicos e genéricos (listas); (iii) atributos são metadados, que alteram a interação dos objetos com funções, mas não suas características básicas.
Aprenderemos também tópicos mais concretos: (i) quais são os tipos de vetores atômicos; (ii) valores NA; (iii) coerção de tipos; (iv) como criar e combinar vetores; (v) o básico dos atributos nome e dimensão, bem como das classes mais comuns no R.
3.2 Famílias de Valores
Na descrição dos tipos de valores, o R também apresenta uma simplicidade muito interessante! Existem duas famílias de tipos de valores: os vetores, e o resto39.
O resto são os tipos internos do R. Os principais estão abaixo, e não existem muitos outros:
- Funções (closures), ambientes, promessas – a serem estudadas no capítulo 6.
- Expressões, símbolos, e chamadas de funções – a serem estudadas no capítulo 7.
-
NULL
, o objeto que denota a ausência de valor – a ser explicado neste capítulo.
Os vetores são os tipos de valores que estamos mais acostumados a lidar. Eles são divididos em dois: temos seis tipos de vetores atômicos, e um tipo de vetores genéricos (mais conhecidos como listas). Cada um será explicado em sua própria seção.
Antes, um contexto geral. Em termos simplistas, na ciência da computação, um escalar é um objeto que que representa um único valor, uma unidade de valor. Uma coleção é um conjunto de valores. Os componentes de uma coleção são chamados de elementos.
Quando todos seus elementos são do mesmo tipo, falamos que uma coleção é atômica, caso contrário, é genérica. Muitas vezes, chamamos uma coleção atômica de vetor, e uma genérica de lista. No R, listas também são referidas como vetores, e portanto existe a nomenclatura “vetores atômicos” e “vetores genéricos”.
3.3 Vetores Atômicos
3.3.1 Escalares e Vetores Atômicos
Vetores Atômicos
- Um vetor atômico é uma coleção de escalares de um mesmo tipo.
- No R, um escalar é uma “coleção de tamanho um”, e portanto, todo escalar é um vetor atômico, não existe diferenciação real entre os dois.
Para esclarece, vamos visualizar. Uma coleção (1, 3, 8)
40 pode ser desenhada como três escalares conectados:
Mas note que cada escalar tem sua própria “caixa”, a estrutura ao redor é inseparável. Isto é, um escalar é a coleção (1)
, não existe o número 1
“sem estar em uma coleção”.
Adicionalmente, note que os resultados dos testes abaixo:
o último teste usa o conceito de subsetting, que será explicado no capítulo 4. A função identical()
é uma forma mais robusta de comparar objetos, ela compara tudo sobre os objetos, e não apenas seus valores.
Por mais que a estrutura não seja separável dos escalares, é possível ter vetores sem elementos. Eu gosto de entender esse fato de um ponto de vista prático: as vezes queremos “contar pro R” que, no futuro, teremos um vetor com conteúdo, então, no presente, criamos um “placeholder”. Vide as funções integer()
, logical()
, etc.
3.3.2 Tipos de Vetores atômicos
É intuitivo que existem diferentes categorias de dados de interesse, mas como foi falado, o conceito de tipo (de valor) é um conceito específico na ciência da computação. Lembre-se, o computador “entende” binário, e o que o R salva na memória do computador são valores em binário.
O que são os tipos, então? O R mantém informação sobre o que cada sequência representa, sobre seu tipo, e este tipo está associado à uma “receita”/“blueprint” de como interpretar essa sequência. Um exemplo hipotético, seria um tipo double, que indica que uma sequência de 64 bits deve ser interpretada como os 32 primeiros bits representando a parte inteira de um número, e os 32 últimos, a parte decimal.
Tipos de vetores atômicos
Os vetores atômicos podem ser de seis tipos, mas quatro são os principais:
-
Logical são os dados booleanos, podem ser
TRUE
ouFALSE
. Podem ser abreviados paraT
eF
41. - Characters são os dados de texto (strings).
-
Integers são números inteiros, e são escritos com um “L” no fim:
12L
. -
Doubles são os números decimais, podem ser escritos na forma decimal
1.245
, científica1.23e4
, ou hexadecimal0xadfe
.- Valores especiais:
Inf
,-Inf
, eNaN
(“not a number”, usado em indefinições matemáticas).
- Valores especiais:
Adicionalmente, existe raw, para dados em binário; e complex, para números complexos. Por fim, existe NULL
que, como dito, não é um vetor, mas pode ser entendido como a “ausência de dado”/“vetor de tamanho zero”.
3.3.3 Combinando Vetores
A função c()
combina (daí o nome) vetores em um mais longo. Ela serve com atômicos ou genéricos, mas por enquanto, vamos usá-la com atômicos: c(TRUE, FALSE)
, c(1, 3.5, 1.23e4)
.
Quando usada com vetores atômicos, c()
coage os inputs a escalares do mesmo tipo, resultando em um outro atomic vector.
Existe uma ordem de prioridade: se houver um character, tudo vira character, fora isso, tudo vira double, depois, integer, e por fim, logical. Veja o exemplo abaixo
Funções que pedem argumentos de um mesmo tipo normalmente os coagem caso eles sejam diferentes, e isso é causa comum de erros.
3.3.4 Funções Úteis
Podemos utilizar a função typeof()
para descobrir o tipo de um objeto.
Para testar se um objeto é de um tipo específico, existem as funções is.logical()
, is.integer()
, is.double()
, e is.character()
. Existem também is.vector()
, is.atomic()
, e is.numeric()
, mas são imprevisíveis.
Na seção de atributos, vamos ver como podemos criar classes em cima dos tipos básicos. Essa complexidade torna os testes de tipo menos confiáveis em alguns contextos, por isso, recomendo usar as variações rlang::is_logical()
e cia. do pacote rlang42, que tem uma relação mais confiável de 1-pra-1 com typeof()
.
Podemos transformar o tipo de um vetor com as.logical()
, as.integer()
, as.double()
, ou as.character()
. Se você for um usuário avançado, leia sobre o pacote vctrs.
A função length()
retorna o tamanho, o número de elementos, de um vetor. Ela tem algumas peculiaridades, mas por enquanto, vamos deixar isso de lado.
A função str()
retorna uma descrição mais detalhada de um objeto, com seu tipo, valores, e atributos. Especialmente como instrumento educacional, ela é sua melhor amiga. Abuse-a.
3.3.5 Valores NA
Todos os tipos explicados assumem um valor especial, o “valor desconhecido”: NA
, “non aplicable”.
A melhor maneira de entender um valor especial é pensar que ele é um conceito. Isto é, o Inf
é o valor double onde x + Inf #> Inf
, x > Inf #> FALSE
, etc., por construção.
O NA
não é diferente, ele representa o conceito de “não sei”. Operações que dependam de um valor desconhecido, intuitivamente, também retornam um valor que não se conhece: 1 + NA #> NA
; NA == NA #> NA
43. Para checar se um valor é NA, use is.na()
.
Por trás dos panos, existe um NA
diferente para cada tipo de vetor atômico (NA_integer_
, etc.). Isso acontece por conta das leis de coerção. Um valor desconhecido numérico pode ser coagido para um valor desconhecido de texto. Essa ideia será explorada nos exercícios.
3.4 Listas
3.4.1 Definição: Listas
Vimos que vetores atômicos não aceitam elementos de tipos diferentes, nem elementos não-escalares, de length maior que 1. Porém, o R permite coleções diferentes, como (1, "a", (1, 2, 3), TRUE, 1)
44.
Vetores Genéricos/Listas
- Uma lista é uma coleção de objetos. Qualquer objeto.
- Note a definição mais flexível/genérica.
- Uma lista é um objeto, portanto listas podem conter outras listas.
- Listas tem seu próprio tipo, list.
Para criar uma lista, usamos a função list()
. As listas também tem suas variantes is.*()
e as.*()
.
Lembre que com vetores atômicos, a “caixa”, a estrutura ao redor dos elementos não era separável. Agora temos essa diferenciação! A lista list(1)
não é um escalar, mas sim uma lista que contém um escalar. Esta é uma diferença importante, e será relevante no capítulo 4. Para esclarecer, vamos visualizar.
Veja o código e a representação visual de cada vetor ao lado.
No capítulo anterior, comentei rapidamente que, por trás dos panos, listas são coleções de referências a objetos, e não coleções de objetos (diretamente). Veja mais em Advanced R seção 2.3.3. Por conta disso, list(x, x)
ocupa bem menos que o dobro do espaço de list(x)
3.4.2 Manipulação Listas
Como listas podem conter outros vetores de tamanhos variados, inclusive outras listas, podem ter formatos bastante complexos.
Falarei sobre algumas manipulações comuns, mas de fato aprendê-las, ficar para os exercícios.
3.4.2.1 Combinando listas
A função list()
cria uma lista envolta dos inputs, enquanto a função c()
(quando usada com alguma lista), concatena Listas.
Lembre-se, a função c()
coage os inputs para um tipo comum, e list está acima de character na ordem de prioridade.
3.4.2.2 Diminuindo a Hierarquia de Listas
- Transformar
list(1, list(2, 3))
emlist(1, 2, 3)
. - Transformar
list(1, 2, 3)
emc(1, 2, 3)
. - Ou, os dois ao mesmo tempo:
list(1, list(2, 3))
emc(1, 2, 3)
.
Para isso, podemos usar a função unlist()
, que por padrão, remove todas as camadas de hierarquia de uma lista (caso 3). Para o caso 1, podemos usar o argumento recursive = FALSE
45. As funções purrr::list_flatten()
e purrr::list_c()
são opções mais consistentes, com menos resultados inesperados. A primeira funciona para o caso 1, e a segunda, para o caso 2.
A função c()
pode ser utilizada para, ao mesmo tempo que combina, simplificar a complexidade de listas, via o argumento recursive = FALSE
. Esse comportamento pode ser útil, mas é confuso e inesperado, prefira ser explícito com primeiro combinar, e depois simplificar.
3.5 Atributos
Os vetores podem carregar mais informações do que apenas os valores de seus elementos, eles podem carregar metadados/atributos, dados sobre o vetor e seus elementos em si.
Praticamente todos os objetos no R podem carregar atributos, mas é raro isso ser útil. Vamos focar em vetores.
Atributos não afetam a “essência” de um vetor, seu dado ou seu tipo, mas podem afetar como ele interage com funções.
Pode-se criar atributos livremente, mas alguns são mais comumente encontrados na natureza:
- names, um vetor character, que nomeia cada elemento de um vetor.
- dim (diminutivo de dimensions), um vetor de inteiros, que reorganiza vetores em matrizes e arrays (em termos simplistas, “matrizes multidimensionais”).
- class, um vetor character, que indica a classe de um vetor, um outro sistema de “tipagem” de objetos, construído em cima dos tipos.
3.5.1 Conceitos Básicos
Algumas funções relacionadas à atributos:
-
atributes()
retorna uma lista com os atributos dex
. -
attr(x, "attr")
retorna o valor do atributo"attr"
. Pode ser utilizada para alterar atributos também. -
structure(x, "attr" = 1 + 1)
adiciona o atributo"attr"
emx
. -
str()
como já explicado, retorna uma visualização dex
incluindo seus atributos.
Os atributos principais tem funções dedicadas: names()
e unname()
, dim()
, class()
, unclass()
. Mas cuidado com class()
, veremos a diante que ela pode retornar uma classe implícita. A maneira mais confiável de checar um atributo é com attr()
.
Atributos são objetos como quaisquer outros, que estão ligados ao objeto “principal” via referências. Como qualquer outro objeto, salvo as exceções, são copied-when-modified. Similarmente, alterar atributos de um objeto o modifica, o que desencadeia a cópia do objeto, se necessário.
3.5.2 Nomes
Nomear um vetor o torna mais compreensível. Adicionalmente, fica mais fácil de fazer referências à seus elementos, veremos isso no capítulo 4.
Podemos nomear um vetor de várias formas:
- Na criação do objeto:
x <- c(a = 1, b = 2, c = 3)
46. - Com
names(x) <- c("a", "b", "c")
, ou usandoattr()
oustructure()
. -
x <- setNames(x, c("a", "b", "c"))
. Considere também a funçãopurrr::set_names()
.
Podemos remover nomes com:
-
names(x) <- NULL
47, ou usandoattr()
oustructure()
. -
x <- unname(x)
. -
x <- setNames(x, NULL)
.
É fácil ver como a estrutura básica fica inalterada. Tente transpor essa ideia para os outros atributos mais complexos a seguir.
3.5.3 Dimensões
Muitas vezes, nossos dados tem uma lógica de organização como a de uma matriz, com linhas e colunas. Algumas vezes, precisamos até de matrizes multi-dimensionais.
3.5.3.1 Criação de Matrizes e Arrays
Um vetor com o atributo dimensão é um vetor que deve ser interpretado como matriz:
m1 <- c(TRUE, FALSE, TRUE, TRUE, FALSE, TRUE)
dim(m1) <- c(2, 3)
m1
#> [,1] [,2] [,3]
#> [1,] TRUE TRUE FALSE
#> [2,] FALSE TRUE TRUE
Ou como array:
O dado é o mesmo, e veremos exemplos de como podemos tratar esse objetos exatamente como vetores, ignorando completamente suas dimensões. Mas, ao mesmo tempo, podemos tratar esses objetos como matrizes ou arrays, e fazer operações matriciais com eles. Use a função str()
!
Ambos podem ser criados diretamente, com as funções matrix()
e array()
:
-
matrix(m1, nrow = 2, ncol = 3)
. -
array(a1, c(2, 3, 2))
.
Também podemos criar e remover dimensões com attr()
ou structure()
.
Note que utilizei vetores atômicos nos exemplos, mas listas também podem ter dimensões. Iremos explorar isso nos exercícios.
Note que podemos ter matrizes com apenas uma linha ou uma coluna, ou arrays com apenas uma dimensão. Eles são diferentes de vetores sem dimensão (NULL-dimensionais), e vão interagir diferentemente com funções (ex: matemática de matrizes).
3.5.3.2 Funções Úteis
Como atributos não alteram a estrutura básica, as funções para vetores tem generalizações para matrizes e arrays:
Vector | Matrix | Array |
---|---|---|
names() |
rownames() , colnames()
|
dimnames() |
length() |
nrow() , ncol()
|
dim() |
c() |
rbind() , cbind()
|
abind::abind() |
— | t() |
aperm() |
is.vector() |
is.matrix() |
is.array() |
Note que adicionar dimensões gerou algumas possibilidades:
- Um tamanho e um atributo de nome para cada dimensão.
- Maneiras diferentes de combinar vetores: por linhas, por colunas, ou por outras dimensões.
- Operação de transposição: com
t()
eaperm()
. - Mais diferenças surgirão no capítulo 4, onde veremos como acessar elementos de vetores com e sem dimensões.
Entender que matrizes e arrays são, em sua base, vetores atômicos, será muito útil para prever como funções vão agir sobre eles.
As funções is.vector()
, is.matrix()
, e is.array()
devem gerar estranheza, já que não à nenhum tipo relacionado à essas coisas. Nos exercícios, veremos exatamente o que essas funções estão testando.
3.5.4 Classes
Outro atributo importante é class, que permite a criação de vetores diferenciados, criados em cima dos tipos básicos. Esse é o conceito vindo da Programação Orientada ao Objeto (OOP), e objeto aqui não é o termo genérico que venho usando, mas sim “uma instância de uma classe”.
Por que criar um segundo sistema de “tipagem”? Porque classes são mais flexíveis, não se precisa criar uma “receita” para interagir com a memória do computador. Qualquer pessoa pode criar uma classe, e colher frutos da programação orientada ao objeto.
Falaremos mais sobre o sistema de OOP do R no capítulo 7, mas o principal a se entender é que funções irão agir de modo diferente, a depender da classe de seu argumento.
Classes podem ser criadas livremente. Abaixo vão algumas muito presentes no R:
- factor são utilizados para dados que podem assumir categorias pré definidas. São construídos em cima de integers.
- Date, POSIXct, e difftime são para datas. São construídos em cima de doubles.
- data.frame e tibble são para tabelas de dados. São construídos em cima de lists.
Entender que classes são construídas em cima dos tipos será muito útil para prever como funções vão agir sobre eles.
muitas vezes queremos esse comportamento de classes, mas sobre objetos mais “elementares”, como vetores “crus” e matrizes. Por conta disso, o R assume implicitamente a classe de um objeto, via a função class()
, mesmo que ele não tenha o atributo classe.
3.5.4.1 Factors
Factors tem o atributo class como "factor"
, e um atributo levels que define os valores/categorias possíveis.
Cuidado, factors comumente geram erros: parecem strings, mas não são. Aplicar manipulações de texto à eles costuma dar errado. Deve-se manipular seus níveis, ou transformar o factor em texto antes. Adicionalmente, vide também stringsAsFactors = sigh.
Também existem os ordered factors, onde indicamos uma ordem para os levels, e costumam ser usados em funções de modelagem e visualização. Vide ordered()
.
3.5.4.2 Datas
Dates: são um double com o atributo class "Date"
. Por trás dos panos são o número de dias entre 01/01/1970 e a data em questão. Para criar, use a função as.Date()
.
Date-times: são um double com o atributo class "POSIXct"
48. Por trás dos panos são o número de segundos entre 01/01/1970 e a hora em questão. Para criar, use a função as.POSIXct()
.
Durations: são um double com o atributo class "difftime"
, que conta a distância entre duas datas. Têm o atributo "units"
que indica como o valor deve ser interpretado. Para criar, use a função as.difftime()
.
Essa classe de vetores são bem complexos, existem muitas complexidades como fusos horários, conversão de formatos, e operações matemáticas. Vou deixar para explicar como manipular essa classe de dado no capítulo 14.
3.5.4.3 Data Frames
Um dataframe é uma representação de uma tabela de dados. Basicamente, uma é uma lista nomeada de vetores, normalmente atômicos, todos de mesmo tamanho. Isto é, similar a:
Como sempre, ter isso em mente ajudará muito a transpor o conhecimento sobre listas para dataframes. Adicionalmente, dataframes tem, implicitamente, dimensões. Portanto, eles apresentarão, muitas vezes, ambos os comportamentos, de lista e de matriz.
Eles tem os atributos names/colnames (nomes das “colunas”), row.names (nomes das “linhas”). They can be accessed with rownames()
and colnames()
. Um data frame tem nrow()
linhas, e ncol()
/length()
colunas.
Data frames são criados com a função data.frame()
, e tem a class "data.frame"
. Também existem as funções is.data.frame()
e as.data.frame()
.
Uma coluna de um data frame pode também ser uma matriz/array (se o número de linhas coincidir), ou uma lista (se o número de elementos coincidir)49. O uso disso é raro.
3.5.4.4 Tibbles
Um Tibble é um sucessor do dataframe, trazido pelo pacote tibble.
Tibbles tem a classe c("data.frame", "tbl_df")
. São “preguiçosos e grosseiros: fazem menos e reclamam mais”:
- Não geram vetores maiores a partir de vetores menores (
data.frame(x = 1:4, y = 1:2)
). - Não mudam nomes não sintáticos.
- Não aceitam rownames, vindo da filosofia que “metadata is data”.
- Um subset de um tibble sempre é um tibble. Mais sobre isso no capítulo 4.
- Não tem matching parcial nos nomes de colunas50.
- Permitem referenciar colunas na hora da criação –
tibble(x = 1:4, y = 2*x)
. - Tem uma melhor visualização no console.
Complemento
Recapitulando
Tipos de Valores
- Existem duas famílias de tipos, os vetores e o resto. Veja a figura 3.1.
- Todos os valores “do dia-a-dia” são vetores. O resto são os tipos internos do R, e serão estudados no futuro.
- Vetores atômicos são coleções de escalares de um mesmo tipo. Listas (vetores genéricos) são coleções de objetos.
- Existem seis tipos de VA, e os quatro principais são: logical, character, integer e double. Listas tem tipo list.
- Valores especiais:
NA
,Inf
,-Inf
, eNaN
.NULL
é um tipo de objeto especial, que indica a ausência de valor.
Manipulações Básicas
- Combinamos qualquer vetor com
c()
. Para listas, temos tambémlist()
.c()
coage os inputs para um mesmo tipo. - Vimos as funções
is.*
(erlang::is_*
) eas.*
para testar e coagir tipos. - Passamos rapidamente por manipulação de listas listas com
unlist()
,purrr::list_flatten()
, epurrr::list_c()
. Também vimospurrr::transpose()
.
Atributos
- Atributos são metadados, que alteram a interação dos objetos com funções, mas não suas características básicas.
- Atributos comuns são names, dim, e class.
- Classes criam um segundo sistema de tipagem, em cima dos tipos básicos. Classes comuns são factor, Date, POSIXct, data.frame, e tibble.
- Vimos como visualizar e alterar os atributos de um objeto.
Dicionário de Funções
Abaixo segue a lista de funções vistaSs neste capítulo.
Categoria | Função | Descrição |
---|---|---|
objetos |
is.*() , rlang::is_*() , as.*() , rlang::as_*()
|
testes e conversões de tipos |
objetos |
typeof()
|
tipo de um objeto |
objetos |
length()
|
tamanho de um objeto |
atributos |
structure() , str()
|
criar e ver a estrutura de um objeto |
atributos |
atributes() , attr()
|
atributos de um objeto |
attrs - name |
names() , colnames() , rownames() , dimnames()
|
nomes por dimensão |
attrs - name |
setNames() , purrr::set_names() , unname()
|
criar nomes |
attrs - dim |
dim() , nrow() , ncol()
|
dimensões |
attrs - dim |
t() , aperm()
|
transpor dimensões |
attrs - class |
class() , unclass()
|
criar e remover classes |
attrs - class |
matrix() , array()
|
criaração de objetos S3 |
attrs - class |
factor() , ordered()
|
criaração de objetos S4 |
attrs - class |
data.frame() , tibble()
|
criaração de objetos S5 |
outros |
I()
|
tratar expressões “as is” em data.frame e formulas |
vetores |
c() , list()
|
criar e combinar vetores |
vetores |
cbind() , rbind() , abind::abind()
|
combinar vetores por dimensão |
vetores |
unlist() , purrr::list_c() , purrr::list_flatten()
|
manipular hierarquia de listas |
Referências
As referências principais deste capítulo são:
- “Advanced R” capítulo “3 - Vectors”.
- “R Language” seções “2.1.1 - Vectors”, “2.1.2 - Lists”, “2.1.6 - NULL”, “2.2 - Attributes”, e “2.3 - Special compound objects”.
- “R Introduction” capítulos “2 a 6”.
- “R Internals” seção “1.3 - Attributes”.
- “R Help” os documentos de ajuda das funções aqui expostas.
Exercícios
os exercícios usam variáveis de mesmo nome. Garanta que você está utilizando as definições corretas. É necessário ver as páginas de ajuda das funções. Rode ?nome_na_funcao
no console.
Tipos de Valores
- Vimos que existem vários tipos de valores. Vamos primeiro falar sobre como se testa por um tipo, e, na próxima questão, como se convertem tipos.
Contei rapidamente que existem as funções is.*
. Vamos estudar um pouco mais sobre elas. O objetivo não é decorar as funções e suas propriedades, mas sim exercitar a habilidade de entender qual operação está realmente sendo feita, e deixar de tratar funções como “caixas pretas”.
- Qual a diferença entre
is.vector()
erlang::is_vector()
?is.vector()
está de acordo com a definição de vetor vista em aula? -
is.numeric()
não testa se um elemento é do tipo double ou integer, o que ela testa? - O número
NA
é finito ou infinito? Como as funçõesis.finite()
eis.infinite()
funcionam? - Dada uma variável
x
, escreva uma expressão que cheque sex
é exatamente igual ao objetoTRUE
. Após escrever sua expressão (!!) compare seu resultado com a funçãoisTRUE()
.
- Falamos sobre como o R converte tipos de valores em outros, para poder juntá-los em um vetor atômico, ou realizar uma operação que precise de tipos comuns. Essa coerção é feita pelas funções
as.*
. Esse é um tema muito importante, mas que vimos apenas de passagem. Vamos explorar alguns casos abaixo.
- Porque
1 < FALSE
é verdadeiro? - As funções
as.*
são pouco estritas, e tentam adivinhar resultados (como vocês já sabem que o R gosta de fazer). Com base nisso, porque1 == "1"
é verdadeiro? Compare comrlang::as_integer("1")
. - Agora com operações aritméticas:
1 + "2"
funciona? ETRUE + 1
? Qual é a regra? - Ocorre coerção na operação
c(list(1, 2), 3)
? Busque na página de ajuda?c()
pela ordem completa de coerção, e a use para justificar sua resposta.
Vetores
- Relembre a definição de vetores atômicos e de listas. Seguindo a convenção do capítulo, desenhe os objetos abaixo.
- Um vetor ‘complicado’:
list(1, list(c(2, 3), c(4, 5))
. - Vetores atômicos:
c(1, 2)
,c(1)
, o primeiro elemento deste, e o primeiro elemento daquele. Qual a diferença entre os três últimos? - Vetores vazios:
list()
,NULL
, einteger(0)
. Qual a length de cada um dos objetos? Qual a intuição desse resultado? Você deve ter tido dificuldade em desenharinteger(0)
, vamos trabalhar nisso. Pense sobrelist()
, como você descreveria seu desenho, você desenhou o que de uma lista? Essa coisa é separável em um vetor atômico? Conclua: é possível desenharinteger(0)
? Qual a diferença entreNULL
einteger(0)
?
- Vimos que os vetores atômicos são a unidade básica de dados no R, e que eles podem ser de seis tipos (sendo quatro os mais importantes). Vimos também que a função
c()
combina vetores. Com base nisso, responda as questões abaixo, sobreNA
eNULL
:
- O vetor atômico
c(1, NULL)
pode existir? Porque? - Qual é o tipo do segundo elemento de
c(1, Inf)
? - Qual é o tipo do segundo elemento de
c(TRUE, NA)
? E dec("1.5", NA)
? O que isso te faz concluir sobre a natureza deNA
? Alguma coerção está acontecendo no segundo caso?
- Falamos rapidamente sobre manipulação de listas. Considere os objetos
x
ey
, e escreva expressões que gerem cada um dos itens em seguida. Ao final, discuta as diferenças depurrr::list_flatten()
,unlist()
, epurrr::list_c()
.
list(list(list(1, 10), list(2, 20)), 1)
list(list(list(1, 10), list(2, 20), 1))
list(list(list(1, 10), list(2, 20), list(1)))
list(1, 10, 2, 20)
c(1, 10, 2, 20)
list(list(1, 2), list(10, 20))
Atributos
- Vamos estudar com mais calma os factors.
- O que acontece com um factor ao alterar seus níveis?
- O que o código abaixo faz? como
f2
ef3
diferem def1
?
- O que faz a função
table()
? Que objeto retorna? Qual seu tipo? Quais seus atributos? Como sua dimensão muda ao adicionar variáveis para tabular?
- Vamos estudar com mais calma os .dataframes
- Pode haver um data frame com zero linhas? E zero colunas?
- O que ocorre se você definir rownames não únicos?
- Se
df
é um data frame, o que ét(df)
? Porque? Et(t(df))
? - O que
as.matrix()
faz quando aplicada a um data frame com colunas de tipos diferentes? Como isso difere de usardata.matrix()
? - Estude o objeto abaixo. As colunas tem a mesma length? O que elas tem igual? Essa é uma medida implícita, ou é um atributo real da coluna?
x <- data.frame(a = 1:2)
x$b <- c(matrix(1, 1, 1), matrix(2, 1, 1))
x$c <- list(matrix(1, 1, 1), matrix(2, 1, 1))
x$d <- data.frame(c1 = factor(c("a", "b")))
- Outros exercícios sobre atributos que não sabia onde colocar :).
- Como
setNames()
funciona? Comounname()
funciona? Olhe o código fonte Muitas funçõesis.*
não estão testando tipos dos objetos, e sim classes. Qual é o método queis.data.frame()
etibble::is_tibble()
utilizam para tal? Eis.array()
eis.matrix()
? Toda matriz é um array? - Explique com detalhe o que a função
identical()
faz, e quais suas opções.