Comunicando os nossos Dados
Clique aqui para assistir o vídeo da aula online do dia 30 de abril de 2021. E o chat.
Até agora, trabalhamos com as tabelas padrões fornecidas pelo R e a opção df_print: paged
no cabeçalho. É só digitar o nome do tibble num chunk e no resultado vai aparecer uma tabela com navegação por página e colunas. Mas existem várias funções de ‘formatação’ que traduz o conteúdo de um tibble para uma tabela bonita no documento final. Elas funcionam como qualquer outra função do R e ficam no final de nosso fluxo de pipes.
A primeira função de formatação de tabelas se chama kable
e fica num pacote se chama knitr
, então temos que instalar (uma vez só, e depois comentado) e abrir o pacote:
library("tidyverse")
library("tidylog")
library("nycflights13")
#install.packages("knitr")
library("knitr")
Agora, seguimos qualquer tibble com %>% kable()
e o R vai produzir uma tabela estática. Tabelas estáticas são simples e limpas, mas geram um risco grande - uma tabela grande será impressa na íntegra. Com um banco de dados de milhares de linhas, isso gera um arquivo enorme e difícil de navegar. Então temos que tomar cuidado: é a sua responsibilidade filter
ou slice
a sua tabela anteriormente para que o resultado final tenha o tamanho desejado.
year | month | day | dep_time | sched_dep_time | dep_delay | arr_time | sched_arr_time | arr_delay | carrier | flight | tailnum | origin | dest | air_time | distance | hour | minute | time_hour |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2013 | 7 | 6 | 1629 | 1615 | 14 | 1954 | 1953 | 1 | UA | 887 | N587UA | EWR | ANC | 418 | 3370 | 16 | 15 | 2013-07-06 16:00:00 |
2013 | 7 | 13 | 1618 | 1615 | 3 | 1955 | 1953 | 2 | UA | 887 | N572UA | EWR | ANC | 404 | 3370 | 16 | 15 | 2013-07-13 16:00:00 |
2013 | 7 | 20 | 1618 | 1615 | 3 | 2003 | 1953 | 10 | UA | 887 | N567UA | EWR | ANC | 418 | 3370 | 16 | 15 | 2013-07-20 16:00:00 |
2013 | 7 | 27 | 1617 | 1615 | 2 | 1906 | 1953 | -47 | UA | 887 | N559UA | EWR | ANC | 388 | 3370 | 16 | 15 | 2013-07-27 16:00:00 |
2013 | 8 | 3 | 1615 | 1615 | 0 | 2003 | 1953 | 10 | UA | 887 | N572UA | EWR | ANC | 434 | 3370 | 16 | 15 | 2013-08-03 16:00:00 |
2013 | 8 | 10 | 1613 | 1615 | -2 | 1922 | 1953 | -31 | UA | 887 | N559UA | EWR | ANC | 411 | 3370 | 16 | 15 | 2013-08-10 16:00:00 |
2013 | 8 | 17 | 1740 | 1625 | 75 | 2042 | 2003 | 39 | UA | 887 | N528UA | EWR | ANC | 404 | 3370 | 16 | 25 | 2013-08-17 16:00:00 |
2013 | 8 | 24 | 1633 | 1625 | 8 | 1959 | 2003 | -4 | UA | 887 | N534UA | EWR | ANC | 428 | 3370 | 16 | 25 | 2013-08-24 16:00:00 |
Uma alternativa de filter
ou slice
que é útil para apresentar uma amostra aleatória da sua tabela (e também para realizar amostras aleatórias em estudos empíricas) é sample_n()
. Escolhemos o número de observações desejadas, e o R vai selecionar aleatoriamente este número de linhas da tabela (Observe que as observações mudam cada vez que rodamos/compilamos o nosso documento):
year | month | day | dep_time | sched_dep_time | dep_delay | arr_time | sched_arr_time | arr_delay | carrier | flight | tailnum | origin | dest | air_time | distance | hour | minute | time_hour |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2013 | 10 | 26 | 1626 | 1625 | 1 | 1843 | 1827 | 16 | DL | 2231 | N357NW | LGA | DTW | 100 | 502 | 16 | 25 | 2013-10-26 16:00:00 |
2013 | 10 | 20 | 1525 | 1536 | -11 | 1651 | 1728 | -37 | UA | 494 | N824UA | LGA | CLE | 69 | 419 | 15 | 36 | 2013-10-20 15:00:00 |
2013 | 9 | 9 | 1848 | 1619 | 149 | 2117 | 1919 | 118 | B6 | 283 | N708JB | JFK | MCO | 115 | 944 | 16 | 19 | 2013-09-09 16:00:00 |
2013 | 8 | 19 | 1330 | 1335 | -5 | 1456 | 1503 | -7 | B6 | 286 | N206JB | JFK | ROC | 57 | 264 | 13 | 35 | 2013-08-19 13:00:00 |
Habilidade Básica de Programação: Aleatoriedade reproduzível
É comum usar funções aleatórias em R para gerar distribuições, simulações e amostras. A função sample_n()
seleciona linhas aleatórias cada vez que rodamos o código ou compilar o relatório com ‘knit’. Isto é útil, mas impede um dos nossos objetivos - a reprodutibilidade, dado que o relatório final fica diferente depois de cada compilação e não temos condições de saber se a variação seja por causa de um erro no código ou por causa da aleatorização.
A solução é a ‘aleatoriedade reproduzível’: Imediatamente antes de roder sample_n()
(fora do pipe, numa linha única), especificamos um ‘seed’. Um seed é como um identificador de uma sequência aleatória. Ele é associado a uma seleção aleatória, mas fixa - ou seja, toda vez que rodarmos o código, a sequência aleatória produzida será a mesma. Para especificar um seed aribtrário, eu sempre gosto de usar um CEP, mas pode escolher qualquer número; não significa nada:
Execute este código (tudo o código, incluindo o set.seed
) umas vezes e confirme que o resultado não muda.
Compile o seu script atual com ‘Knit’: como fica a tabela? O número de linhas não é problemático, mas as colunas saiam do lado direito da página… Também é a nossa responsibilidade limitar o número de colunas para incluir apenas elas que cabem no espaço da tabela final com select
. Dificilmente queremos ver todas as colunas de uma tabela.
month | day | dep_time | carrier | flight | origin | dest |
---|---|---|---|---|---|---|
11 | 2 | 906 | B6 | 1634 | JFK | BTV |
2 | 5 | 1831 | MQ | 3944 | JFK | BWI |
5 | 16 | 1539 | AA | 133 | JFK | LAX |
1 | 30 | 1026 | US | 2169 | LGA | DCA |
5 | 26 | 818 | MQ | 4478 | LGA | DTW |
5 | 30 | 1045 | DL | 1903 | LGA | SRQ |
10 | 1 | 816 | UA | 294 | EWR | MCO |
7 | 8 | NA | DL | 831 | LGA | DTW |
A tabela no relatório final melhorou? Sim. Mas porque investimos todo este esforço? Exige mais trabalho para limitar as linhas e colunas, e não temos as botões para navegar que recebemos com a opção df_print: paged
… Há três motivos para trabalhar com tabelas estáticas:
A tabela é apropriada para publicações em que interatividade não é possível, e funciona melhor com relatórios em Word e PDF (que vamos ver em breve). Compile o seu script para Word (‘Knit to Word’ com a flecha ao lado de ‘Knit’) para ver o resultado. Deve ser muito melhor. Lembre-se que um artigo ou dissertação publicada exige tabelas estáticas.
A necessidade de selecionar as observações e colunas necessárias nos motiva a pensar bem sobre o desenho e a estruta mais apropriados para a nossa tabela. Incluir a tabela inteira cada vez gera documentos grandes e pesados.
A função kable
é muito mais flexível do que as tabelas padrões de R. Podemos personalizar todos os elementos da tabela. Vejamos alguns exemplos abaixo.
Em primeiro lugar, podemos especificar o título da tabela com a opção caption
:
flights %>% sample_n(8) %>%
select(month, day, dep_time, carrier, flight, origin, dest) %>%
kable(caption="Tabela de 8 voos aleatórios")
month | day | dep_time | carrier | flight | origin | dest |
---|---|---|---|---|---|---|
5 | 16 | 822 | B6 | 1172 | EWR | BOS |
7 | 17 | 556 | US | 1629 | LGA | PHL |
9 | 9 | 1717 | UA | 1064 | EWR | BOS |
9 | 6 | 1811 | DL | 926 | EWR | ATL |
5 | 26 | 1055 | WN | 2631 | LGA | MDW |
5 | 19 | 2 | B6 | 739 | JFK | PSE |
8 | 29 | 1239 | EV | 3848 | EWR | CLT |
11 | 7 | 1653 | DL | 1585 | LGA | MCO |
Mais profissional. Em segundo lugar, o kable
deixa mais fácil formatar os resultados númericos - para arredondar os números com as tabelas padrões temos que manualmente usar mutate
para mexer com os valores atuais da tabela. Mas é melhor manter os números ‘corretos’ e completos no tibble, e só ajustar a apresentação na tabela final. Conseguimos realizar uma formatação do número de dígitos com kable
com a opção digits
, que define o número de casas decimais. A nossa tabela até agora só contém variáveis numéricas do tipo ’integer (integral), então vamos calcular velocidade para ilustrar isso:
flights %>% sample_n(8) %>%
mutate(velocidade=distance/air_time) %>%
select(month, day, dep_time, carrier, flight, origin, dest, velocidade) %>%
kable(digits=1)
month | day | dep_time | carrier | flight | origin | dest | velocidade |
---|---|---|---|---|---|---|---|
6 | 18 | 1844 | EV | 4532 | EWR | CHS | 6.2 |
8 | 12 | 724 | AA | 1815 | JFK | MCO | 7.4 |
10 | 27 | 649 | UA | 331 | LGA | ORD | 6.5 |
9 | 5 | 1554 | B6 | 543 | EWR | PBI | 7.1 |
6 | 12 | 1445 | EV | 4434 | EWR | MHT | 5.1 |
6 | 25 | 929 | WN | 3841 | EWR | MDW | 7.0 |
12 | 30 | 931 | EV | 4364 | EWR | MCI | 6.0 |
8 | 11 | 1517 | EV | 4381 | EWR | DTW | 5.9 |
Em terceiro lugar, é comum que a descrição das nossas variáveis na tabela final seja diferente que o nome da variável no script de programação. Isto é natural; em nosso script temos que escrever os nomes das variáveis muitas vezes e um atalho é muito mais eficiente, mas na tabela final o leitor tem que entender o significado da variável com apenas a informação na tabela. O kable
permite especificar nomes de colunas mais complexas, sem renomear elas no tibble original. Por exemplo, o significado de ‘dep_time’ não é óbvio:
flights %>% sample_n(8) %>%
select(month, day, dep_time, carrier, flight, origin, dest) %>%
kable(col.names=c("Mês","Dia","Hora de Partida","Companhia Aérea","Voo","Origem","Destino"))
Mês | Dia | Hora de Partida | Companhia Aérea | Voo | Origem | Destino |
---|---|---|---|---|---|---|
11 | 19 | 1850 | 9E | 2928 | JFK | ORD |
12 | 12 | 1207 | 9E | 3508 | LGA | JAX |
3 | 12 | 1505 | EV | 4572 | EWR | GSP |
8 | 30 | 554 | US | 1909 | LGA | PHL |
3 | 28 | 658 | DL | 1879 | LGA | FLL |
12 | 1 | 541 | EV | 3819 | EWR | CVG |
10 | 11 | 905 | EV | 5813 | EWR | RIC |
10 | 31 | 1651 | EV | 4294 | EWR | SAV |
Finalmente, podemos formatar os números em português (ou qualquer outro local) com o argumento format.args
:
flights %>% sample_n(8) %>%
mutate(velocidade=distance/air_time) %>%
select(month, day, dep_time, carrier, flight, origin, dest, velocidade) %>%
kable(digits=1, format.args=list(big.mark=".", decimal.mark=","))
month | day | dep_time | carrier | flight | origin | dest | velocidade |
---|---|---|---|---|---|---|---|
9 | 21 | 655 | DL | 2.285 | LGA | MCO | 7,9 |
11 | 26 | 952 | 9E | 4.060 | LGA | DAY | 5,8 |
10 | 27 | 1.041 | DL | 954 | LGA | FLL | 6,7 |
6 | 11 | 659 | DL | 763 | JFK | LAX | 7,9 |
1 | 22 | 753 | US | 2.165 | LGA | DCA | 4,0 |
2 | 3 | 2.005 | MQ | 4.555 | LGA | CMH | 6,0 |
5 | 16 | 2.054 | MQ | 4.573 | LGA | DTW | 5,6 |
8 | 10 | 1.832 | B6 | 153 | JFK | PBI | 6,9 |
Para mais opções de kable
, leia aqui, e para saber mais ainda veja o pacote kableExtra
aqui.
Note que existe a opção de gerar tabelas ‘manuais’ diretamente em R markdown, fora de um chunk (detalhes aqui). Não recomendo isso porque a sintaxe é chata para digitar, não temos controle de formatação, e não podemos acessar e transformar o conteúdo no futuro. Se você precisa gerar uma tabela rápida, sempre é recomendado que você gera uma pequena tabela com tibble()
e manda para kable()
, por exemplo:
tibble(Função = c("kable", "opção df_print: paged", "datatable"), Utilidade = c("Word/PDF, relatórios estáticos",
"HTML, relatórios interativos simples", "HTML, relatórios interativos complexos")) %>%
kable()
Função | Utilidade |
---|---|
kable | Word/PDF, relatórios estáticos |
opção df_print: paged | HTML, relatórios interativos simples |
datatable | HTML, relatórios interativos complexos |
A terceira entrada na tabela acima é mais uma opção para gerar tabelas. A função datatable()
(do pacote DT
) tem o mesmo objetivo da opção df_print: paged
; gerar tabelas interativas em HTML. O problema com df_print: paged
é que ela não tem opções para personalizar a tabela final e temos que fazer toda a preparação manualmente. O datatable
é uma função mais avançada que permite personalizações infinitas.
Não entramos nos detalhes de datatable
no tutorial; vocês podem explorar a documentação detalhada aqui. Mas vamos mostrar um exemplo com funcionalidade avançado (filtros de colunas, formatação de números, e coloração de células por valor, neste caso velocidade acima de 7,5):
flights %>%
sample_n(100) %>%
mutate(velocidade=distance/air_time) %>%
select(month, day, dep_time, carrier, flight, origin, dest, velocidade) %>%
datatable(colnames=c("Mês","Dia","Hora de Partida","Companhia Aérea","Voo","Origem","Destino","Velocidade"),
caption="Tabela de 100 voos aleatórios",
filter='top') %>%
formatRound("velocidade",1) %>%
formatStyle('velocidade',
backgroundColor = styleInterval(7, c('white', 'orange'))
)
Exercício 1: Tabelas Bonitas
air_time
) média dos voos de cada aeoporto de origem, ordenado de menor a maior duração. Inclua um título e a formatação apropriada na sua tabela.dep_time
, dep_delay
, carrier
, flight
, dest
, air_time
, distance
. Inclua um título e a formatação apropriada.datatable
. (Não se preocupe com a formatação).Pivot_wide
, Pivot_longer
)Nós temos trabalhado com uma distinção entre variáveis (colunas) e observações (linhas) fixa. Mas a distinção na prática é mais flexível, e a estrutura/organização dos nossos dados depende do nosso objetivo. As vezes vamos querer virar a nossa tabela (tibble) para que as variáveis se transformem em observações múltiplas, ou vice-versa. Esse tipo de operação é muito útil quando trabalhamos com ou queremos criar dados em painel, ou para uma tabela específica em nosso relatório.
É mais fácil demonstar com um exemplo. Veja a tabela de flights
com as variáveis origin
e dest
:
A observação é cada voo, e cada variável é um atributo de cada voo - isto é dados de onde o voo partiu, e onde ele chegou. Mas ambos as variáveis origin
e dest
são a mesma coisa: aeroportos. Podemos imaginar um banco de dados em que desagregamos os voos em dois ‘eventos’ - decolagens e chegadas. Neste banco de dados alternativo, cada observação é um evento e cada voo tem duas entradas (observações, linhas), um decolagem e uma chegada. Isso pode ser útil, por exemplo, se tenhamos muitos dados sobre cada evento/aeroporto, por exemplo os dados de controle de tráfego aéreo.
Para ‘virar’ (pivot) a nossa tabela para o formato mais ‘longo’, usamos a função pivot_longer
. O objetivo de pivot_longer
é converter colunas em observações - no nosso exemplo, converter o evento único “voo” em dois eventos diferentes, pousos e decolagens. Mas não queremos mudar todas as colunas (algumas pertencem ao voo inteiro, como distância, duração); temos que especificar quais colunas queremos virar no argumento cols
. É sempre mais que uma coluna, então temos que especificar as colunas dentro de c()
. As outras colunas nào mencionadas em cols
são colunas ‘identificadoras’ que queremos duplicar para as novas linhas (em nosso exemplo os dados que pertencem ao voo e não ao aeroporto).
Como uma primeira tentativa, o código abaixo é suficiente para virar o nosso tibble:
flights %>% filter(dest=="SNA") %>%
select(month, day, origin, dest) %>%
pivot_longer(cols=c(origin, dest))
Note que agora o nosso banco de dados tem dobro o número de linhas que antes. Cada observação é um evento (decolagen/chegada). As duas colunas ‘origin’ e ‘dest’ agora são linhas separadas, identificadas na colona name
, e o aeroporto que antes era um valor abaixo de ‘origin’ ou ‘dest’ na coluna tem a sua própria coluna value
. Ou seja, em vez de ler os detalhes do primeiro voo horizontalmente no tibble original, agora lemos verticalmente - origem EWR, destino ANC.
O que falta aqui é que os nomes das colunas name
e value
são genéricas e não ajudam entender e descrever os dados. Então é importante renomear as colunas como parte de pivot_longer
. Há duas colunas para nomear: a coluna de name
que contém os nomes de colunas no tibble original (a direção de viagem), que especificamos com o argumento names_to
, e a coluna de valor
que contém os valores no tibble original (os aeroportos), que especificamos com o argumento values_to
.
flights %>% filter(dest=="SNA") %>%
select(month, day, origin, dest) %>%
pivot_longer(cols=c(origin, dest), names_to="Direção", values_to="Aeroporto")
Agora, recebemos o mesmo resultado, mas é bem mais fácil interpretar, pois a natureza do evento é cadastrada na coluna ‘Direção’ e o local do evento fica na coluna ‘Aeroporto’.
Mas ainda existe um problema sério aqui - como sabemos que a primeira linha - o voo com origem em EWR no dia 1 de janeiro é o mesmo voo que chegou no aeroporto SNA no mesmo dia? Não sabemos isso porque não temos dados suficientes para identificar os mesmos voos em linhas separadas. Pode ser que o voo da primeira linha de origem é o mesmo voo na linha 3 ou linha
O problema é que não temos um identificador único para cada voo no banco de dados. Isto é importante para todos os bancos de dados, mas sobretudo quando usamos um ‘pivot’ para mudar a unidade de análise, pois temos que restrear a divisão de uma observação em duas.
Para resolver o problema, temos que incluir colunas suficientes no tibble original. Usando distinct
do tutorial 3, podemos verificar que as colunas month, day, dep_time, carrier, flight, origin e dest são suficientes para identificar cada voo único. O banco de dados original tem 336,776 linhas, ígual o resultado do distinct
com estas variáveis:
flights %>% distinct(month, day, dep_time, carrier, flight, origin, dest)
Agora podemos refazer o pivot_longer
incluindo estas variáveis identificadores:
flights_longo <- flights %>% filter(dest=="SNA") %>%
select(month, day, dep_time, carrier, flight, origin, dest) %>%
pivot_longer(cols=c(origin, dest), names_to="Direção", values_to="Aeroporto")
Perfeito! Agora, dá para rastrear cada voo: Voo UA1496 as 0646 no dia 1 de janeiro tem duas entradas - origem em EWR e chegada em SNA.
É comum que recebemos um banco de dados no formato longo e queremos virar (pivot) para o formato largo. Ou seja, tornar observações em variáveis. Imagine-se que recebemos do fornecedor o banco de dados flights_longo
produzido no chunk anterior. Como reproduzimos o nosso banco de dados bem conhecido, flights
, no formato mais largo?
A função pivot_wider
é exatamante o inverso de pivot_longer
. Em vez de especificar as colunas que queremos virar, especificamos as colunas de ‘identificação’ que não queremos virar no argumento id_cols
; em vez da coluna nova, especificamos a coluna original que contém os nomes das colunas novas, no argumento names_from
; e em vez de valores noves, especificamos a coluna de onde vão sair os valores que vão formar as colunas novas (no argumento values_from
).
Note que com pivot_longer
os argumentos names_to
e values_to
precisam de aspas porque são colunas novas que não existem em nosso tibble. No pivot_wider
os argumentos names_from
e values_from
são colunas atuais em nosso tibble, então não precisam de aspas.
%>%
flights_longo pivot_wider(id_cols = c(month, day, dep_time, carrier, flight), names_from = Direção,
values_from = Aeroporto)
Veja que o resultado aqui tem metade das linhas de flights_longo
, e o mesmo número do nosso banco de dados original. O R peguou os valores da coluna ‘Direção’ e criou uma coluna para cada valor único (uma para ‘origin’, uma para ‘dest’). Os valores destas duas novas colunas são preenchidas da coluna ‘Aeroporto’.
Um atalho para simplificar aqui é quando queremos virar todas as colunas exceto eles mencionados em names_from
e values_from
, podemos pular a especificação de id_cols
:
%>% pivot_wider(names_from=Direção, values_from=Aeroporto) flights_longo
Essas duas funções de pivot são mais avançadas, mas as vezes são essenciais para gerar a estrutura e formato da tabela desejada. É comum que o resultado da nossa análise em R é em formato ‘larga’, mas seria mais bonito imprimir no relatório final no formato ‘longo’. Podemos usar pivot_longer
para rapidamente produzir a tabela desejada. Similarmente, na semana que vem, aprendemos que os gráficos exigem um formato específico - frequentemente o formato ‘longo’ - e estas novas habilidades ajudam bastante.
Exercício 2: Virando Tabelas
pivot_longer
para virar a tabela flights
mais longa, para que cada voo tem duas observações - uma para a hora de partida (dep_time
) e uma outra para a hora de chegada (arr_time
).flights_hora_longo <- flights %>%
pivot_longer(c(arr_time, dep_time), names_to = "Direção", values_to = "Hora")
carrier
, flight
, origin
, dest
e as colunas novas que você gerou na questão 1.%>%
flights_hora_longo select(carrier, flight, origin, dest, Direção, Hora) %>%
sample_n(10) %>%
kable(caption = "Tabela de cada Partida e Chegada")
pivot_wider
para recuperar o banco de dados original de flights
. Verifique que os números de colunas e linhas são íguais.flights_recuperado <- flights_hora_longo %>%
pivot_wider(names_from = "Direção", values_from = "Hora")
As funçoes de filter
, select
, mutate
etc. e o nosso pipe %>%
que compõem o tidyverse têm cerca de 5 anos de idade, mas o R tem mais de 25 anos de idade. O que os usuários fizeram antes do tidyverse?
Existem várias formas de interagir e manipular dados em R, mas nada muda os básicos: existem um script, objetos que podemos salvar, e funções que transformam objetos. Também trabalhamos mais frequentemente com um data.frame, que é um tibble um pouco mais básico.
A maior diferença quando trabalhamos no mundo do ‘R básico’ é na forma em que acessamos e transformamos os valores dentro de um data.frame. Não usamos uma sequência de ações/verbos para separar cada passo; temos que usar uma sintaxe e símbolos bem específicos.
Note que nada nesta seção do tutorial é necessário, e encorajamos vocês a trabalhar dentro do tidyverse sempre que possível, para criar análises mais simples, transparentes e reproduizíveis. Porém, as vezes temos que trabalhar com usuários ou pacotes fora do tidyverse, então é útil entender os conceitos básicos, e também ajuda a entender como o R funciona atrás do interface.
Os símbolos mais importantes no R base são os colchetes. Depois de um data.frame, eles significam que queremos ajustar as colunas e/ou as linhas. Dentro dos colchetes, tem dois ‘espaços’; o primeiro para mexer com as linhas, e o segundo para mexer com as colunas, separado por vírgula.
flights[ , ]
O que inserimos nestes espaços? Vamos começar com as linhas e deixar o espaço para colunas branco. Podemos escolher as linhas para manter por número (como slice
) ou por condição (como filter
):
flights[1:5, ]
flights[distance==200, ]
Error in `[.tbl_df`(flights, distance == 200, ): object 'distance' not found
Hmm, o primeiro funcionou bem, mas o distance==200
não deu certo. As condições no R base são idênticas às que usamos no tidyverse, isso não é o problema. O problema é que no R base, o R não sabe o que significa distance
. Ele busca para um objeto (um data.frame) se chama distance
, mas realmente distance
é uma coluna dentro do objeto flights
. Mesmo que começamos com flights
, temos que informar R que distance
fica dentro de flights
de novo (o motivo para exigir a repetição do objeto é que podemos querer no futuro filtro uma tabela baseado no conteúdo de uma segunda tabela). Digitamos isso assim, separando o data.frame e a coluna com o símbolo $
:
flights[flights$distance==200, ]
Agora funcionou. Como escolhemos colunas em R base? Usamos o segundo espaço, depois da vírgula, para escrever os nomes das colunas desejadas, agora - e em contraste ao tidyverse - em aspas e dentro de um vetor, c()
:
flights[flights$distance==200, c("month","day", "dep_time","origin","dest")]
Compare isso com o equivalente no tidyverse:
Qual você prefere? Para a maioria de tarefas, sobretudo para tarefas mais complexas, é mais intuitivo e transparente usar o tidyverse.
Em alguns momentos os símbolos de R base voltam no tidyverse também. Por exemplo, se quisermos gerar tabelas resumidas, às vezes é útil adicionar uma linha resumida no final, por exemplo um total ou uma média. Para adicionar mais uma linha no final da nossa tabela, podemos usar a função add_row()
no fluxo de pipes, e especificar um argumento para cada coluna na tabela, com o nome de coluna na esquerda do símbolo de íguais, e o valor desejado na direita. É comum adicionar uma linha ‘Total’:
Error in sum(n): invalid 'type' (closure) of argument
Com toda a nossa intuição do tidyverse isso deve funcionar. Mas infelizmente (e por motivos bem chatos da programação de add_row
) não dá. O problema é que o sum(n)
na funcão add_row
não sabe procurar a colona n
na tabela atual (o tibble resultante do último pipe). Ele precisa uma dica para onde procurar. Dentro do tidyverse o símbolo ‘.’ significa o tibble atual, e já aprendemos do R base que o $
nos permitimos especificar uma coluna de um tibble. Então em vez de usar o atalho n
, temos que usar .$n
. Um conjunto de símbolos estranhos, mas funciona:
Leitura para Tutorial 6
Antes da próxima aula, por favor leia R 4 Data Science, Capítulo 3 e ggplot2: Elegant Graphics for Data Analysis, Capítulos 1-5
Desafio 2
O Desafio 2 teste a sua capacidade de organizar, resumir, agrupar, e apresentar um banco de dados para produzir um relatório bonito e claro em HTML.
O prazo para entregar Desafio 2 por email com título “[FLS6397] - D2” à minha conta é 14h, 14/05/2021, antes da próxima aula. Por favor entregue (i) o arquivo .Rmd, e (ii) o arquivo .html.