---
title: "Workshop 4: Data Exploration and Visualization of IRIS Data Set"
author: "oran.k@chula.ac.th"
date: "August 2021"
output: html_document
params:
  intab: TRUE
  
---


```{r,setup,echo=F,include=FALSE}
  #rm(list=ls())
  knitr::opts_chunk$set(echo=TRUE,eval=TRUE,result="show",warning = FALSE,message=FALSE)
  knitr::opts_template$set(hidden = list(
    fig.width = 10, fig.height = 6,
    fig.retina = 2, out.width = '100%',
    echo=!params$intab, eval=!params$intab,
    warning=FALSE,message=FALSE
  ))
  
  knitr::opts_template$set(badcode = list(
    echo=TRUE, eval=FALSE,
    warning=FALSE,message=FALSE
  ))
  
  #intab <- TRUE
```

```{r klippy, echo=FALSE, include=TRUE}
klippy::klippy(position = c('top', 'right'),color = 'darkred')
```

```{css, echo=F}
  .badcodeStyle { background-color: lightpink; font-family: courier }
  
```

```{css, echo=F}
  .hiddenStyle { background-color: lightblue; font-family: courier }
```

# Instruction  # `r if (params$intab) "{.tabset}"`
Read the [instruction](http://ie.eng.chula.ac.th/~oran/classes/compMeth_resources/workshop/workshop04.pdf) carefully and think about how to develop R code to answer each questions. 


## Question 1 ## `r if (params$intab) "{.tabset}"`

##### Consider **`iris`** dataset (one of the most famous dataset in Data Mining) and learn basic command of `data.frame` package

![](iris.png)


### 01: access
##### `data.frame` object has mixed propeties of `matrix()` and `list()`; hence, we can access the object using both methods in four ways. 

```{r}
  ##-- data type
  str(iris)
```

* access as list with name
```{r}

  ##-- access as list
  iris$Sepal.Length[1:10]
```

* access as list with position
```{r}
  iris[[1]][1:10]
```

* access as matrix with row and column
```{r}  
  ##-- access as matrix
  iris[1:10,1]
```

* access as matrix with position and name
```{r}  
  ##-- access as matrix with name
  iris[1:10,"Sepal.Length"]
```

__note__

* we can access all variable as character, but it is, in general, not very useful. 

```{r}
 df.name <- "iris"
 get(df.name)[1:3,]
```




### 02: sampling
##### one way to minimize computation time and reduce operation on `data.frame` is to  sample and review only option of data. Here are two tips: 

* show top/bottom  

```{r}
  
  ##-- show top/bottom 6
  head(iris)
  tail(iris)
```
  
* show random/sample data   

```{r}  
  set.seed(13)
  nSize <- 5
  smp.idx <- sample(1:nrow(iris),nSize)
  iris[smp.idx,]

```

__note__ what is this line do? 

```{r,opts.label="badcode",class.source="badcodeStyle"}
  ##-- This code is NOT execute
  head(iris[-smp.idx,])
```

### 03: view
##### Alternatively, a user may want to screen/check datapoint using commands **`View()`** **`edit()`** and **`fix()`**. 

```{r,opts.label="badcode",class.source="badcodeStyle"}
  ### SOLUTION TO QUESTION 2A ### 
  temp <- iris

  ##-- view only; change are not allow
  View(temp) 
  
  ##-- view and allow change; ???
  fix(temp)  
  
  ##-- view and allow change; ???
  edit(temp) 
```    

__note__

* explain their differences among `View()`, `edit()`, and `fix()`


### 04: misc
##### Before exploring data, here are misc. tips in `data.frame` may useful. 

* dimension and names of columns
```{r}
  ##-- dimension
  nDim <- dim(iris) 
  nCol <- ncol(iris)
  nRow <- nrow(iris)
  
  ##-- column name
  colnames(iris)
  id.DF <- data.frame(id=1:nRow)
```


* combine data.frame
```{r}
  ##-- joint data.frame
  head(cbind.data.frame(id.DF,iris))
  
  ##-- check duplication
  any(duplicated(iris))
  nrow(unique(iris))
  
  ##-- find duplication index
  which(duplicated(iris)==TRUE)
  
```

__note__ 

* identify the pair of duplicated rows and discuss what you want to do with it? 


### 05: `summarytools` ###
##### one trick that we uses to quickly view data is to use `summarytools` package


```{r}

  require(summarytools)
  
  
  print(summarytools::dfSummary(iris),method = "render")

```

__note__ possible command in this package include, `summarytools::freq()`, `summarytools::ctree()` and `summarytools::descr()`. When you should apply these commmands? 

---

## Question 2 ## `r if (params$intab) "{.tabset}"`

##### Re-Consider **`iris`**, explore the data by its classification with R packages. This question is separated into three approaches with the identical result (the background of users and personal experience play important role to how one select approach) : 

* **`base`**  is simple/naive way to explore. no good for large and complex dataset
* **`data.table`** is extension of **`base`** structure using all core in your machine (it is a little complex)
* **`dplyr`** is extension of SQL with a combination of **`data.frame`** and **`tibble`**. It is a part of [tidyverse](https://www.tidyverse.org/), a set of package of data science in R.

---

### `base` ### `r if (params$intab) "{.tabset}"`

#### 01: stat 
##### summarize data using basic prescriptive statistic (mean, median, sd, skewness, kurtosis, sd, IQR, and CV) using **`base`**

```{r}
  ### SOLUTION TO QUESTION 1Aa ### 
  summary(iris)

  ##-- for numeric data
  iris.numer <- iris[,1:4] ##-- only numeric data can be used
  apply(iris.numer,2,mean) ##-- find mean
  symnum(cor(iris.numer)) ##-- find covariance and sign
  
  require(moments)
  
  ##-- skewness is 3rd moment explaing concentration of data
  apply(iris.numer,2,skewness) 
  
  ##-- kurtosis is 4rd moment explaing normaly distributed of data
  apply(iris.numer,2,kurtosis) 
  
  ##-- typical version01 of IQR
  findIQR <- function(x){ quantile(x,prob=0.75) - quantile(x,prob=0.25)} 
  
  ##-- typical version01 of IQR
  apply(iris.numer,2,findIQR)
  
  ##--  inline version of IQR
  apply(iris.numer,2,function(o){ quantile(o,prob=0.75) - quantile(o,prob=0.25)}) 
  
  ##-- find (Coefficient of variation) CV or relative sd
  apply(iris.numer,2,function(o){ sd(o)/mean(o) } )
  
  ##-- find mod of data ##Why use max and table
  apply(iris.numer,2,function(o){ max(table(o))} ) 
  
```


#### 02: query
##### Find data using the following conditions using **`base`** package

* Species is "versicolor" 
* 1.0 $\geq$ Petal.Width $\leq$ 1.5

```{r}
  isSelect <- which(iris$Species == "versicolor" & 
                      iris$Petal.Width > 1.0 & 
                      iris$Petal.Width < 1.5
                    )
  head(iris[isSelect,])
```


#### 03: col select
##### select column in which contains word 'Sepal' in its column names and find their means

```{r}
  ### SOLUTION TO QUESTION 1B ### 

  simCol <- grep("Sepal",names(iris))
  head(iris[,simCol])
  
  aggregate(Sepal.Width~Species,data=iris,mean)
  aggregate(Sepal.Length~Species,data=iris,mean)
```      

#### 04: similar
##### count number of data that contains word 'color' in its Speies using **`base`** package

```{r}
  isSelect <- grepl('color',iris$Species)

  head(iris[isSelect,])
  
  nrow(iris[isSelect,])
```


#### 05: sort 
##### order data in the following order using **`base`** package 

* accending of `Petal.Width`
* decending of `Sepal.Width`
  
```{r}

  iris[order(iris$Petal.Width,-iris$Sepal.Width),]
```


#### 06: mutate
##### count number of data in each Species and summarize using the following criteria


|    type  | width of petal  | length of petal |
|:---------|----------------:|---------------: |   
|    low   | $[0.00,0.75)$   | $[0.0,2.5)$     |    
|    medium| $[0.75,1.75)$   | $[2.5,5.0)$     |
|    high  | $[1.75,\infty)$ | $[5.0,\infty)$  |


```{r,opts.label="badcode",class.source="badcodeStyle"}

  ##-- This code is NOT execute
  iris.DF <- iris

  iris.DF$tWidth  <- ifelse(iris.DF$Petal.Width<0.75,"low",
                            ifelse(iris.DF$Petal.Width<1.75,"mid","high"))
  iris.DF$tLength <- ifelse(iris.DF$Petal.Length<2.50,"low",
                            ifelse(iris.DF$Petal.Length<5.00,"mid","high"))

  ftable(tWidth+tLength~Species,data=iris.DF)
```      


### `data.table` `r if (params$intab) "{.tabset}"`

#### 00: intro
##### `data.table` is a compact and quick package for transforming data in R based on the following structure.

![](dataTable.png)

##### more information:

* [html]!(https://www.listendata.com/2016/10/r-data-table.html)
* [cheat sheet]!(https://github.com/rstudio/cheatsheets/raw/master/datatable.pdf)


#### 01: stat
##### summarize data using basic prescriptive statistic (mean, median, sd, skewness, kurtosis, sd, IQR, and CV) using **`data.table`**

```{r}
  ### SOLUTION TO QUESTION 1Ab ### 
  require(data.table)

  iris.DT <- as.data.table(iris) 
  head(iris.DT)
  
  iris.num.DT <- as.data.table(iris[,1:4])
  iris.num.DT[,lapply(.SD,mean)]
  iris.num.DT[,lapply(.SD,quantile,prob=0.5)]
  iris.num.DT[,lapply(.SD,sd)]

  require(moments)
  iris.num.DT[,lapply(.SD,skewness)]
  iris.num.DT[,lapply(.SD,kurtosis)]
  iris.num.DT[,lapply(.SD,function(o){ quantile(o,prob=0.75) - quantile(o,prob=0.25)})]
```

#### 02: query
##### Find data using the following conditions with and without **`data.table`** package
    
* Species is "versicolor" 
* 1.0 $\geq$ Petal.Width $\leq$ 1.5

```{r}
  head(iris.DT[Species=="versicolor" & between(Petal.Width,1.0,1.5)])
```


#### 03: col select
##### select column in which contains word 'Sepal' in its column names and find their means

```{r}
  ### SOLUTION TO QUESTION 1B ### 

  simCol <- names(iris.DT)[which(names(iris.DT) %ilike% 'Sepal')]
  
  head(iris.DT[,..simCol],3) 
  head(iris.DT[,.SD,.SDcols=simCol],3)
  
  head(iris.DT[,mean(Petal.Length),by=Species])
```      

#### 04: similar
##### count number of data that contains word 'color' in its Speies using **`data.table`**

```{r}
  iris.DT[Species%like% 'color',]
        
  iris.DT[Species%like% 'color',.N]
  
```

__note__
* `data.table::uniqueN()` can use to count number of unique data

```{r}
  uniqueN(iris.DT)
```

#### 05: sort 
##### sort the data in the following order using **`data.table`** packaage order data by 

* accending of `Petal.Width`
* decending of `Sepal.Width`
  
```{r}
  iris.DT[order(Petal.Width,-Sepal.Width)]
```


#### 06: mutate
##### count number of data in each Species and summarize using the following criteria


|    type  | width of petal  | length of petal |
|:---------|----------------:|---------------: |   
|    low   | $[0.00,0.75)$   | $[0.0,2.5)$     |    
|    medium| $[0.75,1.75)$   | $[2.5,5.0)$     |
|    high  | $[1.75,\infty)$ | $[5.0,\infty)$  |
    
    
```{r}
  
  wRange <- c(0.00,0.75,1.75,10.0)
  wLabel <- c("low","mid","high")
  lRange <- c(0.00,2.50,5.00,15.0)
  lLabel <- c("low","mid","high")
  
  iris.DT[,tWidth :=cut(Petal.Width ,wRange,wLabel)]
  iris.DT[,tLength:=cut(Petal.Length,lRange,lLabel)]
  iris.DT[,.N,by=.(tWidth,tLength,Species)]
```


    

### `dplyr`  `r if (params$intab) "{.tabset}"`

#### 00: intro
##### `dplyr` is a part of `tidyr` for Data Transformation. It bases on a function of SQL language that consists of: 


`dplyr`      |  SQL     | desp          |
-------------|----------|---------------|
'select()'   | SELECT   | picks column  |
'filter()'   | WHERE    | picks cases based on their values. |
'group_by'   | GROUP BY | group data    |
'summarise()'| -        | reduces column into a summary.     |
'arrange()'  | ORDER BY | order rows    |
'join()'     | JOIN     | join data     |
'mutate()'   | COLUMN AILAS | adds new column                |


##### more information:

* [html]!(https://www.listendata.com/2016/08/dplyr-tutorial.html)
* [cheat sheet]!(https://github.com/rstudio/cheatsheets/raw/master/data-transformation.pdf)

#### 01: stat
##### summarize data using basic prescriptive statistic (mean, median, sd, skewness, kurtosis, sd, IQR, and CV) using **`dplyr`**


```{r}
  ### SOLUTION TO QUESTION 1Ab ### 
  require(dplyr)

  iris.numer <- iris[,1:4]
  summarise_all(iris.numer,.funs=mean)
  
  require(moments)
  summarise_all(iris.numer,.funs=skewness)
  summarise_all(iris.numer,.funs=function(o){ 
    quantile(o,prob=0.75) - quantile(o,prob=0.25)
    } )
```

__note__

* `glimpse()` is the alternative version of `str()`

```{r}
  require(dplyr) 

  glimpse(iris)
```

#### 02: guery 
##### Find data using the following conditions using **`dplyr`** package
+ Species is "versicolor" 
+ 1.0 $\leq$ Petal.Width $\leq$ 1.5

```{r}
  require(dplyr)  
  
  head(filter(iris,between(Petal.Width,1.0,1.5) & Species == "versicolor"))

  ##-- chain version
  iris %>% filter(between(Petal.Width,1.0,1.5) & Species == "versicolor") -> iris.filter
  head(iris.filter)
```

#### 03: group 
##### select column in which contains word ‘Sepal’ in its column names and find their means  using **`dplyr`** package

```{r,opts.label="badcode",class.source="badcodeStyle"}
  ##-- This code is NOT execute
  select(iris, contains("Sepal"),"Species") -> iris.dp  

  summarise_all(group_by(iris.dp,Species),mean) 
```      

#### 04: similar
#####  count number of data that contains word ‘color’ in its Speies using  **`dplyr`** package 

```{r}
  
  head(filter(iris,grepl("color",Species) ))

  nrow(filter(iris,grepl("color",Species) ))

```    

#### 05: sort
##### order data by using **`dplyr`** package
+ accending of Petal.Width
+ decending of Sepal.Width  

```{r,opts.label="badcode",class.source="badcodeStyle"}
  
  ##-- This code is NOT execute
  head(arrange(iris,Petal.Width,-Sepal.Width))

```  


#### 06: manipulate
##### count number of data in each Species and summarize using the following criteria

|    type  | width of petal  | length of petal |
|:---------|----------------:|---------------: |   
|    low   | $[0.00,0.75)$   | $[0.0,2.5)$     |    
|    medium| $[0.75,1.75)$   | $[2.5,5.0)$     |
|    high  | $[1.75,\infty)$ | $[5.0,\infty)$  |

```{r}
  ### SOLUTION TO QUESTION 1F ###   
  wRange  <- c(0.75,1.75)
  lRange <- c(2.50,5.00)
  
  iris.dply <- iris
  
  iris.dply <- mutate(iris.dply,tWidth=case_when(
    Petal.Width < 0.75 ~ "low",
    Petal.Width > 1.75 ~ "high",
    TRUE ~ "mid"
  ) )
  
  iris.dply <- mutate(iris.dply,tLength=case_when(
    Petal.Length < 2.50 ~ "low",
    Petal.Length > 5.00 ~ "high",
    TRUE ~ "mid"
  ) )
  glimpse(iris.dply)
  
  ftable(tWidth+tLength~Species,data=iris.dply)
```
        
### EXTRA I
##### Use your knowledage to query and mutate `iris` in the following step

* label by its `Petal.Length` into equal groups, (i.e., 'PL.H','PL.M', 'PL.L')
* label by its `Sapel.Length` into equal groups, (i.e., 'SL.H','SL.M', 'SL.L')
* find number rows of each group (there are maximum of $3 \times 3 \times 3=$ 27)
* compute median and sd of column `Petal.Width` of groups
* compute mode and cv of column `Sepal.Width` of groups
* ignore na records

The result should be similar to this table

```{r,opts.label="hidden",class.source="hiddenStyle"}

  pl.cut <- c(0,quantile(iris$Petal.Length,c(1/3,2/3)),10)
  sl.cut <- c(0,quantile(iris$Sepal.Length,c(1/3,2/3)),10)
  
  pl.label<- c('PL.L','PL.M', 'PL.H')
  sl.label<- c('SL.L','SL.M', 'SL.H')
  
  require(data.table)
  iris.DT <- as.data.table(iris)
  iris.DT[ , plText:= cut(Petal.Length,pl.cut,pl.label)]
  iris.DT[ , slText:= cut(Sepal.Length,sl.cut,sl.label)]
  
  iris.DT[ , .(.N,avg.pW=quantile(Petal.Width,0.5),sd.pW=sd(Petal.Width),
              mod.sW=as.numeric(names(sort(table(Petal.Width),T)[1])) ,
               cv.sW=mean(Petal.Width)/sd(Petal.Width) ),
           by=.(plText,slText,Species)][!is.na(sd.pW) & !is.na(cv.sW)]
  
  setorder(iris.DT,plText,slText,Species)

```

### EXTRA II
##### Convert the data into long format and convert it back 

__hint__ There are two possible packages for this task: `reshape2` and `data.table`

* `reshape2::melt()` and `reshape2::dcast()` 
* `data.table::melt()` and `data.table::dcast()`


---

## Question 3 ## `r if (params$intab) "{.tabset}"`

##### Visualize **`iris`** dataset using standard `base` package and then `lattic` package for its classification. Please think about its outliers as you need the observation for the next question:

---

### 01: RECAP 
##### Here are some plots that you should know in the first half. Please recreate them. 

```{r,opts.label="hidden",class.source="hiddenStyle"}
  plot(jitter(iris[,1]),jitter(iris[,2]),cex=0.8,pch=16,col="grey",
       xlab="Length",ylab="Width",main="Sepal Scatter Plot",
       xlim=c(4.0,8.0),ylim=c(1.5,5.5))
  sepal.idx <- c(2,4,17,90,39)
  for(i in sepal.idx){
    text(iris[i,1],iris[i,2],i,cex=0.8)  
  }
  
```
   __NOTE__
   
   * data point 2, 4, 17, 39, and 90 are marked using `text()`
   * `identify()` is a powerful command to do semi-manual labeling

```{r,echo=FALSE}
    oldPar <- par()
```
   
```{r,opts.label="hidden",class.source="hiddenStyle"}
  oldPar <- par()
  par(mfrow=c(2,2))
  for(i in 1:4){
    tempVec <- iris[[i]]
    nameVec <- colnames(iris)[i]
    #distVec <- function(x){ pnorm(x,mean=mean(tempVec),sd=sd(tempVec)) }
    hist(tempVec,col="gray",freq=F,main=nameVec,xlab=nameVec)
    rug(jitter(tempVec))
    #curve(distVec,col="red",add=TRUE)
  }
  
  par(oldPar)
```

   __NOTE__
   
   * tickers under box are points values using `rug()`
   * combine panel can be achieved using `par(mfrow=c(2,2))`

* `boxplot` is a powerful plot to check distribution and outlier.  
   
```{r}
    oldPar <- par()
  boxplot(iris,col="gray")

  par(mfcol=c(2,2))
  boxplot(Sepal.Length~Species,data=iris,col="gray")
  boxplot(Sepal.Width~Species,data=iris,col="gray")
  boxplot(Petal.Length~Species,data=iris,col="gray")
  boxplot(Petal.Width~Species,data=iris,col="gray")
  
  par(oldPar)
```



### 02: rare plot
##### here are some interesting plot, but we rarely uses or cover in the first half


* stem and leaf plot
```{r}
  stem(iris[,2])

```

* sunflower plot

```{r}
  sunflowerplot(iris[,1],iris[,2])
```

---


### 03: `pairs()` and `hists()`
##### observe the dataset visually using **`pairs()`** and **`hist()`** They are basic for understand distribution and relationship 


```{r}
  ### SOLUTION TO QUESTION 2B ### 
  iris.jitter <- apply(iris[,1:4],2,function(o){jitter(o)})
  pairs(iris.jitter,col=iris$Species)  

    
  hist(iris$Sepal.Length,n=10,col="grey",freq = F)
  rug(jitter(iris$Sepal.Length))
  points(density(iris$Sepal.Length),col="red",type="l")
```    
  
### 04: lactic  
##### visualize data by **`bwplot()`** in **`lattice`** package to visualize its classification and compare with **`boxplot()`** 

```{r}
  ### SOLUTION TO QUESTION 2C ### 
  boxplot(Sepal.Length~Species,data=iris,col="grey" )
  boxplot(iris[[2]]~iris$Species,col="grey" ) ##-- alternative version using list
```

##### This is an an advance version of `boxplot()` to plot Species overlapped 

```{r}
  iris.seto <- iris[1:50,]
  iris.virg <- iris[which(iris$Species=="virginica"),]
  iris.vers <- iris[51:100,]
  boxplot(iris.vers[1:4],pch=16,cex=0.5,col="blue")
  boxplot(iris.seto[1:4],pch=16,cex=0.5,col="orange",add=T)
  boxplot(iris.virg[1:4],pch=16,cex=0.5,col="#F0FF00AA",add=T)  
```  

##### Alternative, **`lattice`** package provides a scatter plot using `xyplot()`

```{r}  
  require(lattice)  
  xyplot(iris[[2]]~iris[[1]]|iris[[5]])

  bwplot(Sepal.Length~factor(ceiling(Sepal.Width)) |Species,data=iris,add=T)
```    


### 05: outlier  
##### we can identify outlier of `boxplot()` by saving its in another vairable. For example,

```{r}
  tempBox <- boxplot(iris[[1]]~iris[[5]],plot=F)
  str(tempBox)
```

##### Then, we can identify row id using `which()`. For example,
```{r}
  which(iris[[1]]==tempBox$out & iris[[5]] == tempBox$names[tempBox$group])
```

##### Manually, you can keep record as set of outlier ('outlier1') and combine the sets with command 'union()'.

```{r}
  tempBox <- boxplot(iris[[1]]~iris[[5]],plot=F)
  ol1 <- which(iris[[1]]==tempBox$out & iris[[5]] == tempBox$names[tempBox$group])
  tempBox <- boxplot(iris[[2]]~iris[[5]],plot=F)
  ol2 <- which(iris[[2]]==tempBox$out & iris[[5]] == tempBox$names[tempBox$group])
  
  outlier <- union(ol1,ol2)
  outlier
```

__Note__ other set operation are:
* 'union()' 
* 'intersect()'  
* 'setdiff()'

##### Here are full implementation of such concept

* loop for extracting outlier information of all columns

```{r}
  iris.boxList <- data.frame()
  for(i in 1:4){
    ## i <- 1
    tempBox <- boxplot(iris[[i]]~iris[[5]],plot=F)
    tempDF  <- as.data.frame(tempBox[c("out", "group")])
    tempDF$colName <- i
    tempDF$species <- tempBox$names[tempDF$group]
    iris.boxList <- rbind(iris.boxList,tempDF)
  }
  iris.boxList
```


* loop for finding outliers of all columns

```{r}
  iris.boxList$which <- NULL
  for(i in 1:nrow(iris.boxList) ){
    ## i <- 1
    colIdx  <- iris.boxList$colName[i]
    species <- iris.boxList$species[i]
    value   <- iris.boxList$out[i]
    resRow  <- which( iris[[colIdx]] == value  & iris[[5]]==species)
    iris.boxList$which[i] <- resRow
  }
  iris.boxList
  
```

---

### 06: put together

##### Perhaps, the most important part of data mining is data cleansing as the most time-consuming process and the effects of the next step. Before analyzing, it is important to clean data. The major steps are:

* check for __duplication__
* check for __missing value__
* check for __incorrect__ obvious error, e.g., swap column, out-of-bound, wrong gender
* check for __irregularity__  not-so obvious/strange values usually require investigation, e.g., outlier, noise
* consider __remove__ or __impute__ such data points 

---

##### Because `iris` is a cleaned data, we have to worries only __outlier__. We can manually identify outlier using `identify()` and scatter plot

```{r,opts.label="badcode",class.source="badcodeStyle"}
  ##-- This code is NOT execute
  xAxis <-  iris[,1]
  yAxis <-  iris[,2]  
  plot(xAxis,yAxis)
  identify(xAxis,yAxis)
```  
  
##### Removing outlier can be done latter. Recall that 

```{r}
  iris.boxList

  outlier.Idx <- unique(iris.boxList$which)
  iris.cln <- iris[-outlier.Idx,]

```

##### Alternatively, we can apply __local outlier finding__ `lof()` in `rlof` package that uses the concept of clustering to identify outlier.  


```{r,opts.label="badcode",class.source="badcodeStyle"}  

  ##-- This code is NOT execute
  require(Rlof)
  lof.dist <- lof(iris[,1:4],k=8) 
  isGood   <-  which(lof.dist < 1.2)
  iris.lof <- iris[isGood,]
  pairs(iris.lof[,1:4],col=iris.lof$Species)  
```   


---


## Queston 4 `r if (params$intab) "{.tabset}"`

##### Visual `iris` dataset using `ggplot2` package 

---

### 00: concept
##### `ggplot2` package is a part of `tidyverse` that allows `data.table` and `data.frame` objects to plot and visualize. ggplot2 is based on the grammar of graphics, sepertating components: a data set, a coordinate system, and geoms—visual marks that represent data points. 

![](ggplot.png)

* __DATA__ data.frame or data.table  (_required_) 
* __GEOM_FUNCTION__ plot style (_requied_), e.g., `geom_point()` `geom_box()`
* __MAPPING__ axis, plot component (_requied_) e.g., `aes(x=,y=,fill=)`
* __STAT_FUNCTION__, plot with stat result 
* __FACET_FUNCTION__, show many plot in same figure

```{r,warning=FALSE,echo=FALSE}
  require(ggplot2)
  require(data.table)
  iris.DT <- as.data.table(iris)
  iris.lng <- melt(iris.DT,id.var="Species")
  ggplot(iris.lng, aes(x=variable,y=value,fill=Species)) + geom_violin() -> gg
  gg + facet_grid(cols=vars(Species) ) + xlab("dimension") + ylab("Unit (cm)")
```

__note__ the code is available in the next tab

##### more information:

* [__html__]!(https://ggplot2.tidyverse.org/) 
* [__cheat sheet__]!(https://github.com/rstudio/cheatsheets/blob/master/data-visualization-2.1.pdf)

---

### 01: typical 
##### we will cover a simple geom. 

* Histogram and Density plot

```{r}
  ggplot(iris, aes(Sepal.Width,fill=Species)) + geom_histogram(bins=25) 
```

* Dot plot or overlapped histogram

```{r}
  ggplot(iris) +  geom_dotplot(aes(x=Sepal.Width,fill=Species))
```

* scatter plot
```{r}
  ggplot(iris,aes(x=Sepal.Width,y=Sepal.Length,color=Species)) +  geom_point(position="jitter") + theme_classic()
```

---

### 02: adv
##### In general, `ggplot()` with additional packages can do any form of visualization. Here are some capability that we may use for the team project.  

* facet

```{r}
  require(ggplot2)
  require(data.table)
  iris.DT <- as.data.table(iris)
  iris.lng <- melt(iris.DT,id.var="Species")
  ggplot(iris.lng, aes(x=variable,y=value,fill=Species)) + geom_violin() -> gg
  gg + facet_grid(cols=vars(Species) ) + xlab("dimension") + ylab("Unit (cm)")
```

* 1D density with facet and 2D density 

```{r}
  ggplot(iris.lng, aes(value,color=variable))+ geom_density() + facet_grid(cols=vars(Species) )

  ggplot(iris,aes(x=Sepal.Width,y=Sepal.Length,color=Species)) +  geom_density_2d()
```


* combine filter with plot
```{r}
 ##-- seperate data filter and query 
 iris.DT[Species %like% "color"] %>%
   ggplot(aes(x=Sepal.Width,y=Sepal.Length,color=Species)) + geom_point()
```



__note__

* `%>%` = piping (passing data) command in `dplyr` package  
* `melt` = command to make long table
* `dcast` = command to make short table

---

## Question 5 ## `r if (params$intab) "{.tabset}"`
##### After [marked 30 questions](http://www.ie.eng.chula.ac.th/~oran/classes/compMeth_resources/workshop/scripts/examMarked.csv), an instructor notice a possible cheating of the following ten students.  The questions are TRUE-FALSE question, and instructor has marked '1' for correct answer and '0' for incorrect answer. Can you detect cheaters (source and copier)?

### 00: concept
##### Important Concept ###
* How and what should be compared?
    - answer of each question between two students at a time (*why?*)
    - both get a wrong/right answer (any signal)  
  
* What are measurement of similarity
    - $$ SMC = \frac{\mbox{\# matching attributes}}{\mbox{ \# all attributes}} $$
    - $$ \cos(\mathbf{x},\mathbf{y}) =\frac{\mathbf{x} \cdot \mathbf{y} }{\| \mathbf{x}\| ~\|\mathbf{y}\|}$$

---

### 01: prepare
##### STEP 1: prepare data 

```{r,echo=F}
  ### SOLUTION TO QUESTION 4 STEP 1 ###
  exam.df  <- as.data.frame(read.csv(file="examMarked.csv"))
```

```{r,opts.label="badcode",class.source="badcodeStyle"}
  ##-- This code is NOT execute
  ##-- If error check where is your file
  exam.df <- as.data.frame(read.csv(file="examMarked.csv"))
```


```{r}
  colnames(exam.df) <- c("id",paste( "Q",1:30,sep=""))
  
  stu1 <- exam.df[1,2:31]
  stu2 <- exam.df[2,2:31]
  
  ##-- example of data 
  rbind(stu1,stu2)[,1:10]
```


##### create function that compare two students

```{r}

checkFun <- function(stu1,stu2){
  case00 <- length(which(stu1 == 0 & stu2 == 0))
  case01 <- length(which(stu1 == 0 & stu2 == 1))
  case10 <- length(which(stu1 == 1 & stu2 == 0))
  case11 <- length(which(stu1 == 1 & stu2 == 1))
  return( list(case00=case00,
               case10=case10,
               case01=case01,
               case11=case11) )
}

## test your code
checkFun(stu1,stu2)

```

### 02: compare
##### STEP 2: actual compare student ###
```{r,opts.label="badcode",class.source="badcodeStyle"}
  ##-- This code is NOT execute
  pair <- combn(10,2)
  nPair<- ncol(pair)
  pairResult <- data.frame(stu1ID=pair[1,],stu2ID=pair[2,],
                           case00=rep(NA,nPair),case10=rep(NA,nPair),
                           case01=rep(NA,nPair),case11=rep(NA,nPair))



#nPair <- nrow(pairResult)
for( i in 1:nPair){
  ## i <- 1 ## debug
  stu1ID <- pairResult$stu1ID[i]
  stu2ID <- pairResult$stu2ID[i]
  exam1  <- exam.df[stu1ID,2:31]
  exam2  <- exam.df[stu2ID,2:31]
  compResult <- checkFun(exam1,exam2)
  pairResult$case00[i] <- compResult$case00
  pairResult$case10[i] <- compResult$case10
  pairResult$case01[i] <- compResult$case01
  pairResult$case11[i] <- compResult$case11  
}
ord <- order(pairResult$smc,decreasing = T)
pairResult[ord,]
smc <- (pairResult$case00+ pairResult$case11)/sum(pairResult[,3:6])

```

### 03: stat
##### cor.test

```{r}
  cor.test(as.numeric(exam.df[1,2:31]),as.numeric(exam.df[2,2:31]))
```



---

## Question 6 ## `r if (params$intab) "{.tabset}"`
##### Consider the following visualization example of number of __murders__ in US from **`USArrests`** in package **`datasets`** by state with the thermal map 



```{r,opts.label="hidden",class.source="hiddenStyle"}
  
  ### Example Map ###
  require(maps)
  data <- as.data.frame(USArrests)

  ##-- find Quantile of all data
  intQuantile <- c(0.1,0.25,0.5,0.75,0.9)
  nRange<- length(intQuantile)
  range <- NULL
  for(i in 1:nRange){
    tempProb <- intQuantile[i]
    range <- rbind(range,apply(data,2,quantile,prob=tempProb) )
  }
  rownames(range) <- as.character(intQuantile)
  
  ##-- Assign Colors to states
  colorRange <- heat.colors(nRange+1)
  stateCol <- rep(colorRange[nRange+1],length(data[[1]])) 
  for(j in 1:(nRange-1)){
    ## j<-1
    stateSet <- which(data[[1]] >  range[j,1] & data[[1]] <= range[j+1,1])
    stateCol[stateSet] <- colorRange[nRange+1-j]
  }
  stateSet <- which(data[[1]] >  range[nRange,1])
  stateCol[stateSet] <- colorRange[1]
  
  map('state',col=stateCol,fill=T) ## plot map
  
    ##-- prepare legend
  legendText <- c(paste(c(">",range[nRange,1]),collapse=""))
  for(j in (nRange-1):1){
    legendText <- c(legendText,paste(c(range[j,1],"-",range[j+1,1]),collapse=""))
  }
  legendText <- c(legendText,paste(c("<",range[1,1]),collapse=""))
  legend("bottomright",legend=legendText,pch=rep(15,nRange),col=colorRange,ncol=1,cex=1.0,pt.cex=3.5,y.intersp=0.5,bty="n")
  
  title(colnames(data)[1],cex=1.2)
  
```

---

### 0A: map
##### `maps` package has a build-in worldmap function for visualization `map()`. The details of map may be varied depending on each country. Here is a state map of US.

```{r}
  require(maps)
  map('state',col=c("red","blue","green"),fill=T) 
```

### 0B: data
##### Before integrating with map, we need to know more about **`USArrests`** data. 

```{r}
  data <- as.data.frame(USArrests)
  head(data)
  
  hist(data$Murder,col="grey")
  rug(jitter(data$Murder))
  box()
```


### 0C: color
##### We use `heat.colors()` scheme as color (red = hot; yellow=warm)

```{r}
  intQuantile <- c(0.1,0.25,0.5,0.75,0.9)
  nRange      <- length(intQuantile)
  colorRange  <- sort(heat.colors(nRange+1),decreasing = T)
  pie(rep(1,nRange),col=colorRange)
```

##### put color and map together
```{r}
  valMurder   <- quantile(data$Murder,intQuantile)
  myCol       <- as.character(cut(data$Murder,breaks = c(0,valMurder,20),labels=colorRange))
  
  map('state',col=myCol,fill=T)
  
  
```
### 0D: label 
##### preparation 
```{r}
  ##-- prepare legend
  legendText <- c(paste(c(">",valMurder[nRange]),collapse=""))
  for(j in (nRange-1):1){
    legendText <- c(legendText,paste(c(valMurder[j],"-",valMurder[j+1]),collapse=""))
  }
  legendText <- c(legendText,paste(c("<",valMurder[1]),collapse=""))
  
  legendText
```

##### combine togetther
```{r}

  map('state',col=myCol,fill=T)
  legend("bottomright",legend=legendText,pch=rep(15,nRange),col=colorRange,ncol=1,cex=1.0,pt.cex=3.5
         ,y.intersp=0.5,bty="n")

```

### 01: other maps 
##### base on the previous code blocks, represent other three types of arrest, i.e. Assault, UrbanPop, and Rape with the similar manner with function `plotThermalMap(type=1,quantLv=c(0.1,0.25,0.5,0.75,0.9))`

```{r,opts.label="badcode",class.source="badcodeStyle"}
  ##-- This code is NOT execute and incompleted
  plotThermalMap <- function(type=1,quantLv=c(0.1,0.25,0.5,0.75,0.9)){
    
    data <- as.data.frame(USArrests)

    ##-- This part is intentionaly left out --##
    
    return(0)
  }
  
  plotThermalMap(4)

```

### 02: rscript (DOS)
##### automatically generate the thermal map and export as files (**note** This can be combined and execute with batch file using **`Rscript <fileName>.R`**in DOS)

```{r,opts.label="badcode",class.source="badcodeStyle"}
  ##-- This code is NOT execute   
  typeName <- colnames(USArrests)
  nType    <- length(typeName)
  for(i in 1:nType){
    ## i <- 1 ##-- for debug
    fileName <- paste( c(typeName[i],".png"),collapse="")
    png(fileName,width = 600,height = 600)
    plot.new()
    
    ##-- function from the previous part
    plotThermalMap(i) 
    dev.off()
  }

```

<!--- * select and represent all types of arrests using bar plot with legend 
```{r,opts.label="hidden",class.source="hiddenStyle"}
  ### SOLUTION TO QUESTION 5C ###     
  ##-- convert data in approipate format
  
  data <- t(as.matrix(USArrests))
  colnames(data) <- state.abb
  barplot(data[c(1,4,3,2),],col=c("red","blue","yellow","green"),cex.names = 0.5)

```
--->

---

## Question 7 `r if (params$intab) "{.tabset}"`
##### The final step after understanding patterns and insights of dataset is to prepare data for a model. This involves preparing two data set for training model and testing model.

__note__ This last question is overlapped with the question in the next workshop.

### 01: insights
##### Based on the data exploration so far, list useful insights that can be utilized the model selection.


---

### 02: seperate
##### This can be done using command `sample.int()` or `sample()`. It is very important to indicate `set.seed()`

```{r}
  ##-- using `sample()`
  set.seed(17)
  smpl.idx <- sample(1:nrow(iris),size=30)
  
    ##-- using `sample.int()`
  set.seed(17)
  smpl.idx <- sample.int(nrow(iris),size=30)
  
  iris.test <- iris[smpl.idx,]
  iris.train<- iris[-smpl.idx,]
  
  head(iris.test)
```

__NOTE__ Do the sample balance in term of Spices? If not, is there any solution

---

### 03: build model `r if (params$intab) "{.tabset}"`

##### Different package has different way to build model and activate results. Here are three different examples of three classification packages. 

#### `class::knn()`
##### __k-Nearest Neighborhood__ is the easiest method in classification. It also have the most unique way to build model.  
```{r}
  require(class)
  species.knn <- knn(train=iris.train[,-5],test=iris.test[,-5],
                  cl=iris.train[,5],k=3)  
  
  ftable(iris.test[,5],species.knn)
```

#### `base::glm()`
##### __general linear regression__ is an extension of linear regression model that covers other responses, such as binary  and  positive (poisson). 

```{r}
  ##-- casting factor into number (0-1)
  iris.train$specIdx <- as.numeric(iris.train$Species)
  iris.test$specIdx  <- as.numeric(iris.test$Species)

  species.glm <- glm(specIdx~. -Species,data=iris.train,family ="poisson")
  
  iris.glm    <- round(predict(species.glm,newdata = iris.test,type = "response"))
  ftable(iris.test[,5],iris.glm)  
```


#### `rpart::rpart()`
##### __Recursive Partitioning and Regression Tree__ is one way to build decision tree using greedy algorthm. The method requires pruning and checking of Mellow's $C_p$ to avoid overfitting.

```{r}
  require(rpart)
  iris.rpart <- rpart(Species~.,data=iris.train)  
  
  require(rpart.plot)
  prp(iris.rpart)
  
  species.rpart <- apply(predict(iris.rpart,newdata = iris.test),1,which.max)
  ftable(iris.test[,5],species.rpart)
```

__NOTE__ The detail and how to select a suitable model will be discussed in the next workshop.


#
<!----------- BEGIN: STANDARD OKC FOOTER  -------------------------------->


---

Copyright 2019 &ensp; Oran Kittithreerapronchai.  &emsp; All Rights Reserved.
&emsp; __Last modified:__ `r format(Sys.time(), '%Y-%M-%d, ')` 

<!----------- END: STANDARD OKC FOOTER  ---------------------------------->



<!-------- BEGIN: STANDARD OKC PRINT OUT with SYNTEX  -------------------->
```{r, echo=F,eval=F,include=F} 

##--- CODE PRINING

# curPath <- dirname(rstudioapi::getSourceEditorContext()$path)
# fileName<- basename(rstudioapi::getSourceEditorContext()$path)
# outName <- paste( c(fileName,".html"),collapse="")
# 
# setwd(curPath)
# rmarkdown::render(fileName,params=list(intab=FALSE),output_file = outName)
# library(knitr)
# stitch(
#   script = fileName,
#   system.file("misc", "knitr-template.Rhtml", package = "knitr"),
#   output = outName
# )

#---
```
<!--------- ENDED: STANDARD OKC PRINT OUT with SYNTEX  ------------------->
