其实有2个问题,一个比另一个更高级。
corrplot()
但可以处理因素的方法。我最初尝试使用
chisq.test()
然后计算 p-value 和 Cramer's V 作为相关性,但有太多列需要弄清楚。
那么谁能告诉我是否有一种快速的方法来创建一个“corrplot”,每个单元格都包含 Cramer's V 的值,而颜色由 p-value 渲染。或者任何其他类似的情节。
关于 Cramer 的 V,假设
tbl
是一个二维因子数据框。
chi2 <- chisq.test(tbl, correct=F)
Cramer_V <- sqrt(chi2$/nrow(tbl))
我准备了一个测试数据框,其中包含以下因素:
df <- data.frame(
group = c('A', 'A', 'A', 'A', 'A', 'B', 'C'),
student = c('01', '01', '01', '02', '02', '01', '02'),
exam_pass = c('Y', 'N', 'Y', 'N', 'Y', 'Y', 'N'),
subject = c('Math', 'Science', 'Japanese', 'Math', 'Science', 'Japanese', 'Math')
)
df <- data.frame(
group = c('A', 'A', 'A', 'A', 'A', 'B', 'C'),
student = c('01', '01', '01', '02', '02', '01', '02'),
exam_pass = c('Y', 'N', 'Y', 'N', 'Y', 'Y', 'N'),
subject = c('Math', 'Science', 'Japanese', 'Math', 'Science', 'Japanese', 'Math')
)
df$group <- factor(df$group, levels = c('A', 'B', 'C'), ordered = T)
df$student <- as.integer(df$student)
如果您想获得因子或混合类型的真正相关图,您还可以使用
model.matrix
对所有非数字变量进行 one-hot 编码。这与计算 Cramér V 完全不同,因为它会将您的因子视为单独的变量,就像许多回归模型一样。
然后您可以使用您最喜欢的相关图库。我个人喜欢
ggcorrplot
,因为它的 ggplot2
兼容性。
这是您的数据集的示例:
library(ggcorrplot)
model.matrix(~0+., data=df) %>%
cor(use="pairwise.complete.obs") %>%
ggcorrplot(show.diag=FALSE, type="lower", lab=TRUE, lab_size=2)
AntoniosK的解决方案可以改进如J.D.的建议,还允许混合数据帧,包括标称和数字属性。关联强度是通过偏差校正的 Cramer V 计算名义与名义的关联强度,使用 Spearman(默认)或 Pearson 相关性计算数值与数值,以及使用方差分析计算名义与数值的关联强度。
require(tidyverse)
require(rcompanion)
# Calculate a pairwise association between all variables in a data-frame. In particular nominal vs nominal with Chi-square, numeric vs numeric with Pearson correlation, and nominal vs numeric with ANOVA.
# Adopted from https://stackoverflow.com/a/52557631/590437
mixed_assoc = function(df, cor_method="spearman", adjust_cramersv_bias=TRUE){
df_comb = expand.grid(names(df), names(df), stringsAsFactors = F) %>% set_names("X1", "X2")
is_nominal = function(x) class(x) %in% c("factor", "character")
# https://community.rstudio.com/t/why-is-purr-is-numeric-deprecated/3559
# https://github.com/r-lib/rlang/issues/781
is_numeric <- function(x) { is.integer(x) || is_double(x)}
f = function(xName,yName) {
x = pull(df, xName)
y = pull(df, yName)
result = if(is_nominal(x) && is_nominal(y)){
# use bias corrected cramersV as described in https://rdrr.io/cran/rcompanion/man/cramerV.html
cv = cramerV(as.character(x), as.character(y), bias.correct = adjust_cramersv_bias)
data.frame(xName, yName, assoc=cv, type="cramersV")
}else if(is_numeric(x) && is_numeric(y)){
correlation = cor(x, y, method=cor_method, use="complete.obs")
data.frame(xName, yName, assoc=correlation, type="correlation")
}else if(is_numeric(x) && is_nominal(y)){
# from https://stats.stackexchange.com/questions/119835/correlation-between-a-nominal-iv-and-a-continuous-dv-variable/124618#124618
r_squared = summary(lm(x ~ y))$r.squared
data.frame(xName, yName, assoc=sqrt(r_squared), type="anova")
}else if(is_nominal(x) && is_numeric(y)){
r_squared = summary(lm(y ~x))$r.squared
data.frame(xName, yName, assoc=sqrt(r_squared), type="anova")
}else {
warning(paste("unmatched column type combination: ", class(x), class(y)))
}
# finally add complete obs number and ratio to table
result %>% mutate(complete_obs_pairs=sum(!is.na(x) & !is.na(y)), complete_obs_ratio=complete_obs_pairs/length(x)) %>% rename(x=xName, y=yName)
}
# apply function to each variable combination
map2_df(df_comb$X1, df_comb$X2, f)
}
使用该方法,我们可以轻松分析各种混合变量数据帧:
mixed_assoc(iris)
x y assoc type complete_obs_pairs
1 Sepal.Length Sepal.Length 1.0000000 correlation 150
2 Sepal.Width Sepal.Length -0.1667777 correlation 150
3 Petal.Length Sepal.Length 0.8818981 correlation 150
4 Petal.Width Sepal.Length 0.8342888 correlation 150
5 Species Sepal.Length 0.7865785 anova 150
6 Sepal.Length Sepal.Width -0.1667777 correlation 150
7 Sepal.Width Sepal.Width 1.0000000 correlation 150
25 Species Species 1.0000000 cramersV 150
corrr
包一起使用,例如绘制相关网络图:
require(corrr)
msleep %>%
select(- name) %>%
mixed_assoc() %>%
select(x, y, assoc) %>%
spread(y, assoc) %>%
column_to_rownames("x") %>%
as.matrix %>%
as_cordf %>%
network_plot()
这是一个
tidyverse
解决方案:
# example dataframe
df <- data.frame(
group = c('A', 'A', 'A', 'A', 'A', 'B', 'C'),
student = c('01', '01', '01', '02', '02', '01', '02'),
exam_pass = c('Y', 'N', 'Y', 'N', 'Y', 'Y', 'N'),
subject = c('Math', 'Science', 'Japanese', 'Math', 'Science', 'Japanese', 'Math')
)
library(tidyverse)
library(lsr)
# function to get chi square p value and Cramers V
f = function(x,y) {
tbl = df %>% select(x,y) %>% table()
chisq_pval = round(chisq.test(tbl)$p.value, 4)
cramV = round(cramersV(tbl), 4)
data.frame(x, y, chisq_pval, cramV) }
# create unique combinations of column names
# sorting will help getting a better plot (upper triangular)
df_comb = data.frame(t(combn(sort(names(df)), 2)), stringsAsFactors = F)
# apply function to each variable combination
df_res = map2_df(df_comb$X1, df_comb$X2, f)
# plot results
df_res %>%
ggplot(aes(x,y,fill=chisq_pval))+
geom_tile()+
geom_text(aes(x,y,label=cramV))+
scale_fill_gradient(low="red", high="yellow")+
theme_classic()
请注意,我正在使用
lsr
包通过 cramersV
函数计算 Cramers V。
关于 Q1,如果您首先使用 ?structable(来自同一包)转换数据帧,则可以使用 vcd 包中的 ?pairs.table。这将为您提供一个“马赛克图”的绘图矩阵。这与 corrplot()
所做的不太一样,但我怀疑这将是一个更有用的可视化。
df <- data.frame(
...
)
library(vcd)
st <- structable(~group+student+exam_pass+subject, df)
st
# student 01 02
# subject Japanese Math Science Japanese Math Science
# group exam_pass
# A N 0 0 1 0 1 0
# Y 1 1 0 0 0 1
# B N 0 0 0 0 0 0
# Y 1 0 0 0 0 0
# C N 0 0 0 0 1 0
# Y 0 0 0 0 0 0
pairs(st)
还有各种其他适合分类-分类数据的图,例如筛图、关联图和压力图(请参阅我关于
交叉验证的问题:列联表的筛图/马赛克图的替代方案 )。如果您不喜欢马赛克图,您可以编写自己的基于对的函数,将您想要的任何内容放入上部或下部三角形面板中(请参阅我的问题:将矩阵与 qq-plots)。请记住,虽然绘图矩阵非常有用,但它们仅显示边际投影(要更全面地理解这一点,请参阅我在 CV 上的回答:多元回归中“控制”和“忽略”其他变量之间有区别吗? ,这里:三维散点图的替代品)。 关于Q2,您需要编写一个自定义函数。