You are on page 1of 7

4/7/2018 r - How to interpret a QQ plot - Cross Validated

_
Cross Validated is a question and Here's how it works:
answer site for people interested in
statistics, machine learning, data
analysis, data mining, and data
visualization. Join them; it only takes a
minute: 
Anybody can ask Anybody can The best answers are voted
  a question   answer   up and rise to the top
Sign up

How to interpret a QQ plot

I am working with a small dataset (21 observations) and have the following normal QQ plot in R:

Seeing that the plot does not support normality, what could I infer about the underlying distribution? It seems to me that a distribution more skewed to the
right would be a better fit, is that right? Also, what other conclusions can we draw from the data?

r   self­study   data­visualization   inference   qq­plot

edited Jun 6 '14 at 15:13 asked Jun 5 '14 at 10:44
gung ♦ JohnK
97.6k 28 228 470 11.2k 7 31 76

7 You're correct that it indicates right skewness. I'll try to locate some of the posts on interpreting QQ plots. – Glen_b ♦ Jun 5 '14 at 10:56

2 You don't have to conclude; you just need to decide what to try next. Here I would consider square rooting or logging the data. – Nick Cox Jun 5 '14 at 12:56
https://stats.stackexchange.com/questions/101274/how-to-interpret-a-qq-plot 1/7
4/7/2018 r - How to interpret a QQ plot - Cross Validated
y j y q g gg g

9 Tukey's Three­Point Method works very well for using Q­Q plots to help you identify ways to re­express a variable in a way that makes it approximately normal. For instance, picking the
penultimate points in the tails and the middle point in this graphic (which I estimate to be (−1.5, 2) , (1.5, 220) , and (0, 70) ), you will easily find that the square root comes close to
linearizing them. Thus you can infer that the underlying distribution is approximately square root normal. – whuber ♦ Jun 5 '14 at 13:09

3 @Glen_b The answer to my question has some information: stats.stackexchange.com/questions/71065/… and the link in the answer has another good source:
stats.stackexchange.com/questions/52212/qq­plot­does­not­match­histogram – tpg2114 Jun 5 '14 at 16:26

What of this? Does the QQ plot show notmally distributed data? !enter image description here – David Mar 2 '15 at 9:17

2 Answers

If the values lie along a line the distribution has the same shape (up to location and scale) as the
theoretical distribution we have supposed.

Local behaviour: When looking at sorted sample values on the y­axis and (approximate) expected
quantiles on the x­axis, we can identify from how the values in some section of the plot differ locally
from an overall linear trend by seeing whether the values are more or less concentrated than the
theoretical distribution would suppose in that section of a plot:

As we see, less concentrated points increase more and more concentrated points than supposed
increase less rapidly than an overall linear relation would suggest, and in the extreme cases
correspond to a gap in the density of the sample (shows as a near­vertical jump) or a spike of constant
values (values aligned horizontally). This allows us to spot a heavy tail or a light tail and hence,
skewness greater or smaller than the theoretical distribution, and so on.

Overall apppearance:

Here's what QQ­plots look like (for particular choices of distribution) on average:

But randomness tends to obscure things, especially with small samples:

https://stats.stackexchange.com/questions/101274/how-to-interpret-a-qq-plot 2/7
4/7/2018 r - How to interpret a QQ plot - Cross Validated

Note that at n = 21 the results may be much more variable than shown there ­ I generated several
such sets of six plots and chose a 'nice' set where you could kind of see the shape in all six plots at the
same time. Sometimes straight relationships look curved, curved relationships look straight, heavy­tails
just look skew, and so on ­ with such small samples, often the situation may be much less clear:

It's possible to discern more features than those (such as discreteness, for one example), but with 
n = 21 , even such basic features may be hard to spot; we shouldn't try to 'over­interpret' every little

wiggle. As sample sizes become larger, generally speaking the plots 'stabilize' and the features
become more clearly interpretable rather than representing noise. [With some very heavy­tailed
distributions, the rare large outlier might prevent the picture stabilizing nicely even at quite large sample
sizes.]

https://stats.stackexchange.com/questions/101274/how-to-interpret-a-qq-plot 3/7
4/7/2018 r - How to interpret a QQ plot - Cross Validated
You may also find the suggestion here useful when trying to decide how much you should worry about
a particular amount of curvature or wiggliness.

A more suitable guide for interpretation in general would also include displays at smaller and larger
sample sizes.

edited Sep 20 '17 at 4:15 answered Jun 5 '14 at 12:49
Glen_b ♦
193k 21 352 676

12 This is a very practical guide, thank you very much for gathering all that information. –  JohnK  Jun 5 '14 at 12:57

2 I understand that it is shape and type of deviation from linearity what matters here, but still it looks odd that both axes are
labeled " ... quantiles " and one axis goes as 0.2 0.4 0.6 and the other goes as ­2 ­1 0 1 2. Again it looks ok that some data
points are within middle 40% of a theoretical distribution, but how can they be distributed between 3% of their own
distributon, as the y­axis on your lower­right­most plot suggests? – Macond Dec 2 '14 at 15:27

1 @Macond The y­axis shows the raw values of the data, not their quantiles. I agree that standardizing the y­axis would
make things much clearer, and I have no idea why R doesn't do this by default. Could someone shed some light on this? –
 Gordon Gustafson Feb 22 '15 at 19:50 

3 @GordonGustafson in respect of your first comment to Macond there's a very good reason why you don't standardize the
data ­­ because a QQ plot is a display of the data! It's designed to show information in the data you supply to the function
(it would make as much sense to standardize the data you supply to a boxplot or a histogram). If you transform it, it's no
longer a display of the data (though the shape in the plot may be similar, you no longer show the location or scale on the
plot). I'm not sure what it is you think would be clearer in a standardized plot ­ can you clarify? – Glen_b ♦ Feb 23 '15 at
4:23 

2 @ZiyaoWei No, a uniform really has very light tails ­­ arguably, no tails at all. Everything is within 2 MADs of the center.
The first paragraph of this answer gives a clear, general, way to think about what 'heavier­tailed' means. – Glen_b ♦ May
14 '15 at 3:48 

I made a shiny app to help interpret normal QQ plot. Try this link.

In this app, you can adjust the skewness, tailedness (kurtosis) and modality of data and you can see
how the histogram and QQ plot change. Conversely, you can use it in a way that given the pattern of
QQ plot, then check how the skewness etc should be.

For further details, see the documentation therein.

I realized that I don't have enough free space to provide this app online. As request, I will provide all
three code chunks:  sample.R ,  server.R  and  ui.R  here. Those who are interested in running this app
may just load these files into Rstudio then run it on your own PC.

The  sample.R  file:

# Compute the positive part of a real number x, which is $\max(x, 0)$. 
positive_part <‐ function(x) {ifelse(x > 0, x, 0)} 
 
# This function generates n data points from some unimodal population. 
# Input: ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ 
# n: sample size; 
# mu: the mode of the population, default value is 0. 
# skewness: the parameter that reflects the skewness of the distribution, note it is not 
#           the exact skewness defined in statistics textbook, the default value is 0. 
# tailedness: the parameter that reflects the tailedness of the distribution, note it is 
#             not the exact kurtosis defined in textbook, the default value is 0. 
 
# When all arguments take their default values, the data will be generated from standard  
# normal distribution. 
 
random_sample <‐ function(n, mu = 0, skewness = 0, tailedness = 0){ 
  sigma = 1 
 
  # The sampling scheme resembles the rejection sampling. For each step, an initial data 
point 
  # was proposed, and it will be rejected or accepted based on the weights determined by 
the 
  # skewness and tailedness of input.  
  reject_skewness <‐ function(x){ 
      scale = 1 
      # if `skewness` > 0 (means data are right‐skewed), then small values of x will be 
rejected 
      # with higher probability. 
      l <‐ exp(‐scale * skewness * x) 
      l/(1 + l) 
  } 

https://stats.stackexchange.com/questions/101274/how-to-interpret-a-qq-plot 4/7
4/7/2018 r - How to interpret a QQ plot - Cross Validated
 
  reject_tailedness <‐ function(x){ 
      scale = 1 
      # if `tailedness` < 0 (means data are lightly‐tailed), then big values of x will be 
rejected with 
      # higher probability. 
      l <‐ exp(‐scale * tailedness * abs(x)) 
      l/(1 + l) 
  } 
 
  # w is another layer option to control the tailedness, the higher the w is, the data 
will be 
  # more heavily‐tailed.  
  w = positive_part((1 ‐ exp(‐0.5 * tailedness)))/(1 + exp(‐0.5 * tailedness)) 
 
  filter <‐ function(x){ 
    # The proposed data points will be accepted only if it satified the following 
condition,  
    # in which way we controlled the skewness and tailedness of data. (For example, the  
    # proposed data point will be rejected more frequently if it has higher skewness or 
    # tailedness.) 
    accept <‐ runif(length(x)) > reject_tailedness(x) * reject_skewness(x) 
    x[accept] 
  } 
 
  result <‐ filter(mu + sigma * ((1 ‐ w) * rnorm(n) + w * rt(n, 5))) 
  # Keep generating data points until the length of data vector reaches n. 
  while (length(result) < n) { 
    result <‐ c(result, filter(mu + sigma * ((1 ‐ w) * rnorm(n) + w * rt(n, 5)))) 
  } 
  result[1:n] 

 
multimodal <‐ function(n, Mu, skewness = 0, tailedness = 0) { 
  # Deal with the bimodal case. 
  mumu <‐ as.numeric(Mu %*% rmultinom(n, 1, rep(1, length(Mu)))) 
  mumu + random_sample(n, skewness = skewness, tailedness = tailedness) 
}

The  server.R  file:

library(shiny) 
# Need 'ggplot2' package to get a better aesthetic effect. 
library(ggplot2) 
 
# The 'sample.R' source code is used to generate data to be plotted, based on the input 
skewness,  
# tailedness and modality. For more information, see the source code in 'sample.R' code. 
source("sample.R") 
 
shinyServer(function(input, output) { 
  # We generate 10000 data points from the distribution which reflects the specification 
of skewness, 
  # tailedness and modality.  
  n = 10000 
 
  # 'scale' is a parameter that controls the skewness and tailedness. 
  scale = 1000 
 
  # The `reactive` function is a trick to accelerate the app, which enables us only 
generate the data 
  # once to plot two plots. The generated sample was stored in the `data` object to be 
called later. 
  data <‐ reactive({ 
    # For `Unimodal` choice, we fix the mode at 0. 
    if (input$modality == "Unimodal") {mu = 0} 
 
    # For `Bimodal` choice, we fix the two modes at ‐2 and 2. 
    if (input$modality == "Bimodal") {mu = c(‐2, 2)} 
 
    # Details will be explained in `sample.R` file. 
    sample1 <‐ multimodal(n, mu, skewness = scale * input$skewness, tailedness = scale * 
input$kurtosis) 
    data.frame(x = sample1)}) 
 
  output$histogram <‐ renderPlot({ 
    # Plot the histogram. 
    ggplot(data(), aes(x = x)) +  
      geom_histogram(aes(y = ..density..), binwidth = .5, colour = "black", fill = 
"white") +  
      xlim(‐6, 6) + 
      # Overlay the density curve. 
      geom_density(alpha = .5, fill = "blue") + ggtitle("Histogram of Data") +  
      theme(plot.title = element_text(lineheight = .8, face = "bold")) 
  }) 
 
  output$qqplot <‐ renderPlot({ 
    # Plot the QQ plot. 
    ggplot(data(), aes(sample = x)) + stat_qq() + ggtitle("QQplot of Data") +  
      theme(plot.title = element_text(lineheight=.8, face = "bold")) 
    }) 
})

https://stats.stackexchange.com/questions/101274/how-to-interpret-a-qq-plot 5/7
4/7/2018 r - How to interpret a QQ plot - Cross Validated
Finally, the  ui.R  file:

library(shiny) 
 
# Define UI for application that helps students interpret the pattern of (normal) QQ 
plots.  
# By using this app, we can show students the different patterns of QQ plots (and the 
histograms, 
# for completeness) for different type of data distributions. For example, left skewed 
heavy tailed 
# data, etc.  
 
# This app can be (and is encouraged to be) used in a reversed way, namely, show the QQ 
plot to the  
# students first, then tell them based on the pattern of the QQ plot, the data is right 
skewed, bimodal, 
# heavy‐tailed, etc. 
 
 
shinyUI(fluidPage( 
  # Application title 
  titlePanel("Interpreting Normal QQ Plots"), 
 
  sidebarLayout( 
    sidebarPanel( 
      # The first slider can control the skewness of input data. "‐1" indicates the most 
left‐skewed  
      # case while "1" indicates the most right‐skewed case. 
      sliderInput("skewness", "Skewness", min = ‐1, max = 1, value = 0, step = 0.1, ticks 
= FALSE), 
 
      # The second slider can control the skewness of input data. "‐1" indicates the most 
light tail 
      # case while "1" indicates the most heavy tail case. 
      sliderInput("kurtosis", "Tailedness", min = ‐1, max = 1, value = 0, step = 0.1, 
ticks = FALSE), 
 
      # This selectbox allows user to choose the number of modes of data, two options are 
provided: 
      # "Unimodal" and "Bimodal". 
      selectInput("modality", label = "Modality",  
                  choices = c("Unimodal" = "Unimodal", "Bimodal" = "Bimodal"), 
                  selected = "Unimodal"), 
      br(), 
      # The following helper information will be shown on the user interface to give 
necessary 
      # information to help users understand sliders. 
      helpText(p("The skewness of data is controlled by moving the", strong("Skewness"), 
"slider,",  
               "the left side means left skewed while the right side means right 
skewed."),  
               p("The tailedness of data is controlled by moving the", 
strong("Tailedness"), "slider,",  
                 "the left side means light tailed while the right side means heavy 
tailedd."), 
               p("The modality of data is controlledy by selecting the modality from", 
strong("Modality"), 
                 "select box.") 
               ) 
  ), 
 
  # The main panel outputs two plots. One plot is the histogram of data (with the 
nonparamteric density 
  # curve overlaid), to get a better visualization, we restricted the range of x‐axis to 
‐6 to 6 so  
  # that part of the data will not be shown when heavy‐tailed input is chosen. The other 
plot is the  
  # QQ plot of data, as convention, the x‐axis is the theoretical quantiles for standard 
normal distri‐ 
  # bution and the y‐axis is the sample quantiles of data.  
  mainPanel( 
    plotOutput("histogram"), 
    plotOutput("qqplot") 
  ) 


)

edited May 25 '17 at 18:22 answered Dec 4 '15 at 19:06
Zhanxiong
3,150 10 20

1 Looks like your Shiny app's capacity has maxed out. Maybe you could just provide the code – rsoren Jan 21 '16 at 19:38

1 @rsoren added, hope it helps and I am looking forward to hearing suggestions. – Zhanxiong Feb 17 '16 at 18:59 

Nice work, @Zhanxiong I really appreciate it :) – Vilmantas Jan 6 '17 at 19:01 

Very nice! I would suggest also adding options for changing the sample size and a degree of randomness. – Itamar May 23
'17 at 6:38

Link is not available !!!! @Zhanxiong – Alireza Sanaee Sep 1 '17 at 15:45

https://stats.stackexchange.com/questions/101274/how-to-interpret-a-qq-plot 6/7
4/7/2018 r - How to interpret a QQ plot - Cross Validated

https://stats.stackexchange.com/questions/101274/how-to-interpret-a-qq-plot 7/7

You might also like