R语言 绘制因子(分类数据)和混合类型的等价相关矩阵?

vdzxcuhz  于 2023-02-01  发布在  其他
关注(0)|答案(4)|浏览(309)

实际上有两个问题,一个比另一个更高级。

Q1:我正在寻找一种类似于corrplot()但可以处理因子的方法。

我最初尝试使用chisq.test(),然后计算 * p值 * 和 Cramer 's V 作为相关性,但需要计算的列太多了。因此,有人能告诉我是否有一种快速的方法来创建一个“corrplot”,使每个单元格包含 Cramer' s V 的值,而颜色由 * p值 * 呈现。或任何其他类型的类似图。
关于 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')
)

Q2:然后,我想计算混合类型 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')
) 
df$group <- factor(df$group, levels = c('A', 'B', 'C'), ordered = T)
df$student <- as.integer(df$student)
rslzwgfq

rslzwgfq1#

如果您想要因子或混合类型的真正相关图,您还可以使用model.matrix对所有非数值变量进行one-hot编码。这与计算Cramér 's 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)

vc6uscn9

vc6uscn92#

@AntoniosK的解决方案可以按照@J.D.的建议进行改进,以允许混合数据框架,包括标称 * 和 * 数值属性。关联强度的计算包括使用偏差校正Cramer's V的标称与标称、使用Spearman(默认)或Pearson相关的数值与数值以及使用ANOVA的标称与数值。

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)
}

使用该方法,我们可以容易地分析大范围的混合变量 Dataframe :
x一个一个一个一个x一个一个二个x
这也可以与优秀的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()

dfty9e19

dfty9e193#

下面是一个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包来计算Cramers V(使用cramersV函数)。

vh0rcniy

vh0rcniy4#

关于Q1,如果首先使用?structable(来自同一个包)转换 Dataframe ,则可以使用vcd包中的?pairs.table。这将为您提供mosaic plots的绘图矩阵。这与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)

还有很多其他的图也适用于分类-分类数据,比如筛图、关联图和压力图(请参见我在Cross Validated上的问题:您可以编写自己的基于pairs的函数,将您想要的内容放入上三角形面板或下三角形面板中(请参阅我的问题:Pairs matrix with qq-plots),如果你不喜欢马赛克图。只要记住,虽然绘图矩阵是非常有用的,他们只显示边缘投影(要更全面地理解这一点,请参阅我的回答CV在这里:Is there a difference between 'controlling for' and 'ignoring' other variables in multiple regression?,此处:Alternatives to three dimensional scatter plot)。
关于Q2,您需要编写一个自定义函数。

相关问题