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:
flights_longo %>% pivot_wider(names_from=Direção, values_from=Aeroporto)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.