How to analyze categorical data?

I have a data set where one of the variables is categorical with two levels, Yes and No. I am trying to run the function cor() to find the correlation between all the variables but since the categorical variable is not numbers I get the prompt that x must be numeric.

I've read a few places that I don't need to change the variable to a dummy variable because R does it for me but I can't run the function I need. How can I fix this?

• You could also do an MCA Multiple Correspondence Analysis with dudi.acm{ade4} or MCA{FactoMineR} is a data analysis technique for nominal categorical data, used to detect and represent underlying structures in a data set.
– Rafael Díaz
Sep 14, 2018 at 4:51
• Correlation does not make sense for categorical data, what you want is probably a t-test. Sep 14, 2018 at 8:57
• You didn't tell us what is the goal of your analysis, or what your variables represent in the "real world". Please do so, otherwise there is little we can do. Sep 14, 2018 at 10:29
• Correlation makes perfect sense for a numeric binary variable, which often is best scored as 0 and 1, and another numeric variable. Whether it is helpful for your project is harder to say. I can't see that you need or are well advised to jump to MCA as what you are telling us, I think, is that one variable is binary but the others are counted or measured. Otherwise I agree strongly with @kjetilbhalvorsen Sep 14, 2018 at 11:58
• How to get what you want in R is presumably trivial to experienced R users, but I am not one, and that kind of detail is off-topic here. Nevertheless someone may give you a hint. Sep 14, 2018 at 12:02

If there is only one such column, and the data type is string, such that values are "Yes" and "No", you can change the datatype with as.numeric(as.factor()) and this converts it to a factor variable which works with cor()

library(MASS)  # contains many sample datasets
data(Pima.te) # diabetes dataset, has 1 Yes/No column
str(Pima.te)


Result

'data.frame':   332 obs. of  8 variables:
$npreg: int 6 1 1 3 2 5 0 1 3 9 ...$ glu  : int  148 85 89 78 197 166 118 103 126 119 ...
$bp : int 72 66 66 50 70 72 84 30 88 80 ...$ skin : int  35 29 23 32 45 19 47 38 41 35 ...
$bmi : num 33.6 26.6 28.1 31 30.5 25.8 45.8 43.3 39.3 29 ...$ ped  : num  0.627 0.351 0.167 0.248 0.158 0.587 0.551 0.183 0.704 0.263 ...
$age : int 50 31 21 26 53 51 31 33 27 29 ...$ type : Factor w/ 2 levels "No","Yes": 2 1 1 2 2 2 2 1 1 2


-- change the datatype:

Pima.te$type <- as.numeric(as.factor(Pima.te$type))
str(Pima.te)


Result

'data.frame':   332 obs. of  8 variables:
$npreg: int 6 1 1 3 2 5 0 1 3 9 ...$ glu  : int  148 85 89 78 197 166 118 103 126 119 ...
$bp : int 72 66 66 50 70 72 84 30 88 80 ...$ skin : int  35 29 23 32 45 19 47 38 41 35 ...
$bmi : num 33.6 26.6 28.1 31 30.5 25.8 45.8 43.3 39.3 29 ...$ ped  : num  0.627 0.351 0.167 0.248 0.158 0.587 0.551 0.183 0.704 0.263 ...
$age : int 50 31 21 26 53 51 31 33 27 29 ...$ type : num  2 1 1 2 2 2 2 1 1 2 ...


--

cor(Pima.te)


Result:

         npreg     glu      bp    skin      bmi     ped     age   type
npreg  1.00000 0.09548 0.17948 0.08521 -0.01591 0.07550 0.66738 0.2409
glu    0.09548 1.00000 0.19468 0.23517  0.27415 0.23521 0.23456 0.5199
bp     0.17948 0.19468 1.00000 0.20480  0.33819 0.03123 0.32488 0.1705
skin   0.08521 0.23517 0.20480 1.00000  0.65854 0.13691 0.09458 0.2677
bmi   -0.01591 0.27415 0.33819 0.65854  1.00000 0.12672 0.04733 0.3147
ped    0.07550 0.23521 0.03123 0.13691  0.12672 1.00000 0.15301 0.2517
age    0.66738 0.23456 0.32488 0.09458  0.04733 0.15301 1.00000 0.2830
type   0.24090 0.51994 0.17052 0.26772  0.31468 0.25167 0.28297 1.0000


This result probably does not make any sense, and maybe you prefer dummy variables 1 and 0 instead of 2 and 1, but you get the idea.

If there are many such variables in your dataframe, it is a different story and I would use

dplyr::mutate_if(is.factor, as.numeric) #pseudocode


but that's maybe too complicated for now

The cor function is R's standard function for computing Pearson, point-biserial, Spearman and Kendall correlations. Even though many of those work well on ordinal data, the function does not work on the data type ordered which is R's data type for ordinal data.

I consider it a quirk of the language, that you have to convert ordinal data to numeric datatypes in order to compute Spearman or Kendall correlations.

Beware that after you converted this, there is no safety measure in place to restrict you from computing "Pearson" correlations from orginally ordinal data.

x1 <- ordered(c("A", "B", "C", "D", "A", "A"))
x2 <- ordered(c("a", "b", "c", "d", "d", "b"))

# this does not work
cor(x1, x2, method = "spearman")

#this works:
cor(as.numeric(x1), as.numeric(x2), method = "spearman")

# BEWARE this will run without throwing an error
cor(as.numeric(x1), as.numeric(x2), method = "pearson")


It may be a more sensible approach to not use as.numeric but to use rank for the conversion. Spearman correlation thus becomes Pearson correlation on ranks, which is statistically correct:

> cor(as.numeric(x1), as.numeric(x2), method = "spearman")
[1] 0.3947368
> cor(rank(x1), rank(x2))
[1] 0.3947368


Pearson r which assumes interval data (and is used in many correlation analysis) does not make sense for categorical data. Spearman's rho assumes at least ordinal data and if your data is ordinal that might make more sense.

If you assume a theoretical interval latent variable or you have data that has two levels only than polychoric correlations may make sense. From old memory its often recommended for likert data for example.

I work in SAS so I don't know if you can do these in R.