Nesta atividade, continuaremos utilizando os dados modificados do
dataset iris
do pacote vegan
com os dados
coletados por Edgar Anderson.
O primeiro passo é identificar os campos presentes no dataset:
str
para conferir os tipos de dados em
cada colunaunique
a cada coluna usando a outra
função de loop lapply
<- read.csv("data/iris_mod.csv", header = T)
iris
lapply(iris, unique)
## $Sepal.Length
## [1] 5.1 5.4 5.0 4.7 5.2 4.4 4.5 4.6 7.0 5.5 6.3 6.0 6.7 6.2 6.1 6.4 5.8 5.7 6.5
## [20] 7.3 7.7 7.2 7.9 6.8 5.9 4.8 4.9 6.9 6.6 5.6 7.4 4.3 5.3 7.1 7.6
##
## $Sepal.Width
## [1] 3.5 3.4 3.3 3.2 4.1 3.0 2.3 3.8 2.7 2.2 3.1 2.8 2.9 2.4 2.5 2.6 3.9 4.0 3.6
## [20] 3.7 4.2 2.0 4.4
##
## $Petal.Length
## [1] 1.4 1.7 1.6 1.5 1.2 1.3 1.9 4.7 4.0 3.9 4.4 4.5 4.3 5.0 3.8 5.1 4.2 3.0 5.8
## [20] 6.3 5.5 6.7 6.0 5.6 6.4 5.9 1.0 4.9 4.6 3.6 4.1 4.8 3.5 6.1 5.3 6.9 5.7 5.4
## [39] 5.2 1.1 3.3 3.7 6.6
##
## $Petal.Width
## [1] 0.3 0.2 0.5 0.4 0.1 1.4 1.3 1.6 1.0 1.5 1.7 1.1 1.2 1.9 2.2 1.8 2.0 2.1 2.4
## [20] 2.3 0.6 2.5
##
## $Species
## [1] "Iris setosa" "Iris versicolor" "Iris virginica"
##
## $amostra
## [1] "A18" "A21" "A24" "A27" "A30" "A33" "A36" "A39" "A42" "A45"
## [11] "A48" "A51" "A54" "A57" "A60" "A63" "A66" "A69" "A72" "A75"
## [21] "A78" "A81" "A84" "A87" "A90" "A93" "A96" "A99" "A102" "A105"
## [31] "A108" "A111" "A114" "A117" "A120" "A123" "A126" "A129" "A132" "A135"
## [41] "A138" "A141" "A144" "A147" "A150" "A3" "A6" "A9" "A12" "A15"
## [51] "A17" "A20" "A23" "A26" "A29" "A32" "A35" "A38" "A41" "A44"
## [61] "A47" "A50" "A53" "A56" "A59" "A62" "A65" "A68" "A71" "A74"
## [71] "A77" "A80" "A83" "A86" "A89" "A92" "A95" "A98" "A101" "A104"
## [81] "A107" "A110" "A113" "A116" "A119" "A122" "A125" "A128" "A131" "A134"
## [91] "A137" "A140" "A143" "A146" "A149" "A2" "A5" "A8" "A11" "A14"
## [101] "A19" "A22" "A25" "A28" "A31" "A34" "A37" "A40" "A43" "A46"
## [111] "A49" "A52" "A55" "A58" "A61" "A64" "A67" "A70" "A73" "A76"
## [121] "A79" "A82" "A85" "A88" "A91" "A94" "A97" "A100" "A103" "A106"
## [131] "A109" "A112" "A115" "A118" "A121" "A124" "A127" "A130" "A133" "A136"
## [141] "A139" "A142" "A145" "A148" "A1" "A4" "A7" "A10" "A13" "A16"
##
## $lat
## [1] 48.93597 48.54050 48.32984
##
## $lon
## [1] -64.84098 -64.76651 -65.51233
##
## $date
## [1] "1929-12-01" "1930-02-13"
##
## $site
## [1] "Site1" "Site2" "Site3"
Aqui podemos identificar que temos 150 amostras e nomes de espécies associados às amostras, além de atributos (e.g., Petal.Length, Sepal.Width) associados a cada espécie. Também existem dados de coordenadas dos sites e datas das amostragens.
Podemos aproveitar para investigar algumas características dos dados e fazer um controle de qualidade. Por exemplo, verificar se existem valores discrepantes nas variáveis numéricas ou se existem valores faltantes.
Inicialmente, vamos fazer uma inspeção visual da distribuição dos valores numéricos.
%>%
iris select(Species, Sepal.Length:Petal.Width) %>%
pivot_longer(cols = -Species, names_to = "variavel", values_to = "valores") %>%
ggplot(aes(x = valores, fill = Species)) +
geom_histogram() +
facet_wrap(~ variavel, scales = 'free_x') +
theme_classic() +
theme(legend.position = "bottom") +
labs(x = "tamanho (mm)") +
scale_fill_discrete(
expression(bold("Species:")),
labels = c(expression(italic("Iris setosa")),
expression(italic("Iris versicolor")),
expression(italic("Iris virginica"))))
Aqui podemos observar a variação dos dados que tendem a tem distribuição unimodal, mas sem valores extremos.
Para checar as demais variáveis, vamos utilizar o pacote
validate
. Neste pacote é possível indicar os padrões
esperados de cada variável e verificar quais observações violam os
limites indicados. Para isso são definidas as regras (e.g. valores de
latitude
entre -90 e 90, variável site
como
caracter). Para mais informações, basta acessar o vignette
do pacote validate
<- validator(in_range(lat, min = -90, max = 90),
rules in_range(lat, min = -180, max = 180),
is.character(site),
is.numeric(date),
all_complete(iris))
<- confront(iris, rules)
out summary(out)
## name items passes fails nNA error warning
## 1 V1 150 150 0 0 FALSE FALSE
## 2 V2 150 150 0 0 FALSE FALSE
## 3 V3 1 1 0 0 FALSE FALSE
## 4 V4 1 0 1 0 FALSE FALSE
## 5 V5 1 1 0 0 FALSE FALSE
## expression
## 1 in_range(lat, min = -90, max = 90)
## 2 in_range(lat, min = -180, max = 180)
## 3 is.character(site)
## 4 is.numeric(date)
## 5 all_complete(iris)
plot(out)
Avaliando os dados, podemos ver que não existem inconsistências e que já possuímos quase todos os campos obrigatórios para o sistema Darwin Core (DwC).
Em seguida, um passo importante é checar se os nomes utilizados dos táxons são válidos.
get_tsn
do pacote
taxize
. Esta função permite investigar na base de dados do
Integrated Taxonomic Information
System se a nomenclatura aplicada aos táxons é válida ou se
necessita de atualização.# check taxa
<- iris %>%
species distinct(Species) %>%
pull() %>%
c("Iris murchosa", .) %>% # inserimos uma espécie fictícia para teste
get_tsn() %>%
data.frame() %>%
bind_cols(Species = iris %>%
distinct(Species) %>%
pull() %>%
c("Iris murchosa", .))
## ══ 4 queries ═══════════════
## ✖ Not Found: Iris murchosa
## ✔ Found: Iris setosa
## ✔ Found: Iris versicolor
## ✔ Found: Iris virginica
## ══ Results ═════════════════
##
## • Total: 4
## • Found: 3
## • Not Found: 1
Podemos observar que nossa impostora (Iris murchosa) não existe na base de dados do ITIS.
Os campos de match
e pattern_match
indicam
que as espécies são válidas e, o campo uri
indica o
endereço único para checar a espécie no ITIS. Este campo
uri
será utilizado na planilha occurrence
do
sistema event core
.
Sabendo-se que podemos prosseguir sem corrigir os táxons, agora é necessário renomear as variáveis de acordo com o DwC.
O primeiro passo é criar uma identidade única para as menores
unidades de ocorrência dos táxons (occurrenceID
) e das
amostras (eventID
).
Em seguida são adicionadas as informações de espécie
(uri
) e renomeados os campos de acordo com o DwC.
Por fim, são adicionados campos recomendados que detalham as
variáveis presentes no dataset
(eg. sistema de coordenadas,
datum, amostrador etc)
OBS: os dados das coordenadas são fictícios e o nome do amostrador é baseado em informação do pacote
vegan
(para checar, carregue o pacotevegan
e digite?iris
)
<- iris %>%
iris_1 ::mutate(eventID = paste(site, date, sep = "_"), # create indexing fields
dplyroccurrenceID = paste(site, date, amostra, sep = "_")) %>%
left_join(species %>%
select(Species, uri)) %>% # add species unique identifier
::rename(decimalLongitude = lon, # rename fields according to DwC
dplyrdecimalLatitude = lat,
eventDate = date,
scientificName = Species,
scientificNameID = uri) %>%
mutate(geodeticDatum = "WGS84", # and add complimentary fields
verbatimCoordinateSystem = "decimal degrees",
georeferenceProtocol = "Random coordinates obtained from Google Earth",
locality = "Gaspe Peninsula",
recordedBy = "Edgar Anderson",
taxonRank = "Species",
organismQuantityType = "individuals",
basisOfRecord = "Human observation")
Com os campos adicionados na planilha já podemos iniciar a construção das três matrizes necessárias para inserir os dados em repositórios baseados em ocorrências e dados acessórios como o GBIF.
Os campos obrigatórios na planilha de eventos
(eventCore
) são: * eventID = indica os eventos únicos de
amostragem * eventDate = data da amostragem no formato YYYY-MM-DD (ano
com 4 dígitos, mês com 2 dígitos e dia com 2 dígitos) * decimalLongitude
= longitude indicada em graus decimais * decimalLatitude = latitude
indicada em graus decimais * verbatimCoordinateSystem = tipo de
coordenadas * geodeticDatum = Datum das coordenadas
Os termos padronizados do DwC podem ser encontrados no site do DwC.
Nesta planilha, apenas os campos relacionados às amostras e características gerais do conjunto de dados são selecionadas.
## create eventCore
<- iris_1 %>%
eventCore select(eventID, eventDate, decimalLongitude, decimalLatitude, locality, site,
%>%
geodeticDatum, verbatimCoordinateSystem, georeferenceProtocol) distinct()
O próximo passo é derivar as ocorrências únicas presentes no dataset. Como ocorrência deve ser considerada a ocorrência única de determinada espécie.
## create occurrence
<- iris_1 %>%
occurrences select(eventID, occurrenceID, scientificName, scientificNameID,
%>%
recordedBy, taxonRank, organismQuantityType, basisOfRecord) distinct()
Por fim, podemos associar atributos a cada ocorrência, neste caso, medidas morfométricas das flores das espécies indicadas. Aqui também devem ser adicionados os campos onde são detalhados os tipos de atributos associados às ocorrências, por exemplo, indicar que as medidas foram tomadas de indivíduos e medidas em centímetros. Os nomes das medidas foram renomeados para seguir padrões de boas práticas.
## create measurementsOrFacts
<- iris_1 %>%
eMOF select(eventID, occurrenceID, recordedBy, Sepal.Length:Petal.Width) %>%
pivot_longer(cols = Sepal.Length:Petal.Width,
names_to = "measurementType",
values_to = "measurementValue") %>%
mutate(measurementUnit = "cm",
measurementType = plyr::mapvalues(measurementType,
from = c("Sepal.Length", "Sepal.Width", "Petal.Width", "Petal.Length"),
to = c("sepal length", "sepal width", "petal width", "petal length")))
O penúltimo passo é um rápido controle de qualidade para checar se
todas as planilhas tem os mesmos valores de eventID
.
Afinal, este campo é o elo entre todas as planilhas.
# check if all eventID matches
setdiff(eventCore$eventID, occurrences$eventID)
## character(0)
setdiff(eventCore$eventID, eMOF$eventID)
## character(0)
setdiff(occurrences$eventID, eMOF$eventID)
## character(0)
# check NA values
%>%
eMOF filter(is.na(eventID))
## # A tibble: 0 × 6
## # … with 6 variables: eventID <chr>, occurrenceID <chr>, recordedBy <chr>,
## # measurementType <chr>, measurementValue <dbl>, measurementUnit <chr>
%>%
occurrences filter(is.na(eventID))
## [1] eventID occurrenceID scientificName
## [4] scientificNameID recordedBy taxonRank
## [7] organismQuantityType basisOfRecord
## <0 rows> (or 0-length row.names)
Tudo parece OK! Agora podemos remover os arquivos intermediários e
deixar apenas os que serão publicados, para então salvá-los como arquivo
*.csv
.
rm(list = setdiff(ls(), c("eventCore", "occurrences", "eMOF")))
<- list(eventCore, occurrences, eMOF)
files <- c("DF_eventCore","DF_occ","DF_eMOF")
data_names dir.create("Dwc_Files")
for(i in 1:length(files)) {
<- paste0(getwd(), "/", "DwC_Files")
path write.csv(files[[i]], paste0(path, "/", data_names[i], ".csv"))
}
Agora já está tudo pronto para subir os dados para o repositório ou compartilhar diretamente. Só não esqueça dos metadados!!
Colabore, compartilhe, e cite as fontes!