Shiny 中的数据争论:在 k 均值聚类分析后绘制新争论的数据
Data wrangling in Shiny: plotting newly wrangled data after k-means clustering analysis
我正在尝试构建一个数据分析仪表板,我正在使用 Shiny,我对它比较陌生。我的仪表板的一个功能是对用户生成的数据使用 k 均值聚类。我可以使聚类分析正常工作,但我希望能够在完成初始聚类分析后对单个聚类进行探索性数据分析。此外,我想在 Shiny 中使用反应式数据框来执行此操作,以便如果用户更改仪表板上的值,分析会刷新,包括 post- 聚类探索性内容。
首先,这是我在仪表板服务器代码和相关库中使用的一些函数,所以 运行 首先是这些:-
#libraries===================================================================
library(ids)
library(tidyverse)
library(dplyr)
library(shiny)
library(ggplot2)
library(shinydashboard)
library(shinyWidgets)
library(factoextra)
#functions required==========================================================
#scale
scale_this <- function(x){
(x - mean(x, na.rm=TRUE)) / sd(x, na.rm=TRUE)
}
#wss plot
wssplot <- function(data, nc = 15, seed = 1234) {
wss <- (nrow(data) - 1) * sum(apply(data, 2, var))
for (i in 2:nc) {
set.seed(seed)
wss[i] <- sum(kmeans(data, centers = i)$withinss)
}
plot(1:nc,
wss,
type = "b",
xlab = "Number of Clusters",
ylab = "Within groups sum of squares")
}
这里是这个例子的模拟数据框的代码:-
#Create my mock data frame============================================
set.seed(123)
randomid<-random_id(333)#from 'ids' library
Duration<-c(floor(runif(10000, min=1, max=1000)))
mockdf<-cbind(randomid, Duration)
mockdf<-as.data.frame(mockdf)
mockdf$Duration<-as.numeric(mockdf$Duration)
我的UI代码:-
#UI============================================================================
ui<-fluidPage(
titlePanel('Minimal example'),
tabsetPanel(
#=============================================kmeans clustering==================================================
tabPanel("User Type Discovery",
sidebarLayout(
sidebarPanel(width = 4,numericInput('ksolution', 'Select k solution', 5),
pickerInput('userselect', 'Which users do you want to include:',
choices = unique(mockdf$randomid), options = list('actions-box'=TRUE),multiple = T)),
mainPanel(fluidRow(
column(12, plotOutput("elbowplot")),
column(12, plotOutput("clustplot")),
column(12, plotOutput("clust_dens")),
column(12, DT::dataTableOutput('Clusterdf'))))
)
)
)
)
还有我的服务器代码:-
#SERVER===========================================================
server<-function(input,output,session){
#create reactive dataframe
rval_df <-reactive({
mockdf
})
#=============================================kmeans clustering==================================================
rval_UserData<-reactive({
rval_df()%>%
filter(randomid %in% input$userselect)%>%
group_by(randomid)%>%
summarise(Count=n(),MeanDuration=mean(Duration),SDDuration=sd(Duration))%>%
mutate(SDDuration=if_else(is.na(SDDuration),0,SDDuration),
Cluster=as.factor(rval_kclust()$cluster))
})
#create a scaled dataset for the clustering
rval_cluster_df<-reactive({
rval_df()%>%
filter(randomid %in% input$userselect)%>%
group_by(randomid)%>%
summarise(Count=n(),MeanDuration=mean(Duration),SDDuration=sd(Duration))%>%
mutate(SDDuration=if_else(is.na(SDDuration),0,SDDuration),
Count=scale_this(Count),
MeanDuration=scale_this(MeanDuration),
SDDuration=scale_this(SDDuration))%>%
select(Count,MeanDuration,SDDuration)
})
#cluster algorithm
rval_kclust<-reactive({
kmeans(rval_cluster_df(), centers = input$ksolution)
})
output$clustplot<-renderPlot({
factoextra::fviz_cluster(rval_kclust(), data = rval_cluster_df())
})
output$elbowplot<-renderPlot({
wssplot(rval_cluster_df())
})
output$Clusterdf<- DT::renderDataTable({
rval_UserData()
})
}
shinyApp(ui, server)
当您运行 shinyApp(ui,server)
时,点击应用程序下拉框中的“Select全部”按钮以运行聚类。
现在,这就是我想要做的。由于我已将簇号分配回 rval_UserData()
,我希望能够将此分配簇号合并到 mockdf
,因此我可以在 [=19] 上使用 ggplot2
生成绘图=] 变量并生成汇总表,所有这些都在集群级别。我更喜欢使用反应式数据框来做到这一点,因此绘图将根据 UI.
中的 ksolution
输入进行刷新
这是我尝试将簇号合并回 mockdf
的一些尝试,然后尝试绘制密度图:-
rval_cluster_merged_df<-reactive({
merge(mockdf(), rval_UserData(), by="randomid")
#outside of shiny, this would be a quick way to paste the cluster number back onto the mock dataframe
})
output$clust_dens<-renderPlot({
dd<-rval_cluster_merged_df()
ggplot(dd,aes(x=Duration, colour=Cluster, group=Cluster))+
geom_density()+ggtitle("Cluster density plot")+scale_x_log10()
})
这就是我得到的,请参阅错误消息:-
很明显我做错了,但是任何正确方向的指示都将不胜感激!提前谢谢你:)
您需要对所有 input$abc
变量使用 req()
,并且 eval_tidy
因为它们不是标准变量。如下所示对您的服务器功能进行小幅更新即可解决您的问题。
server<-function(input,output,session){
#create reactive dataframe
rval_df <-reactive({
mockdf
})
#=============================================kmeans clustering==================================================
rval_UserData<-reactive({
req(input$userselect)
userselect <- eval_tidy(input$userselect)
rval_df()%>%
filter(randomid %in% userselect)%>%
group_by(randomid)%>%
summarise(Count=n(),MeanDuration=mean(Duration),SDDuration=sd(Duration))%>%
mutate(SDDuration=if_else(is.na(SDDuration),0,SDDuration),
Cluster=as.factor(rval_kclust()$cluster))
})
#create a scaled dataset for the clustering
rval_cluster_df<-reactive({
req(input$userselect)
userselect <- eval_tidy(input$userselect)
rval_df()%>%
filter(randomid %in% userselect)%>%
group_by(randomid)%>%
summarise(Count=n(),MeanDuration=mean(Duration),SDDuration=sd(Duration))%>%
mutate(SDDuration=if_else(is.na(SDDuration),0,SDDuration),
Count=scale_this(Count),
MeanDuration=scale_this(MeanDuration),
SDDuration=scale_this(SDDuration))%>%
select(Count,MeanDuration,SDDuration)
})
#cluster algorithm
rval_kclust<-reactive({
req(input$ksolution)
centers <- as.numeric(eval_tidy(input$ksolution))
kmeans(rval_cluster_df(), centers = centers)
})
output$clustplot<-renderPlot({
factoextra::fviz_cluster(rval_kclust(), data = rval_cluster_df())
})
output$elbowplot<-renderPlot({
wssplot(rval_cluster_df())
})
output$Clusterdf<- DT::renderDataTable({
rval_UserData()
})
rval_cluster_merged_df<-reactive({
merge(rval_df(), rval_UserData(), by="randomid")
})
output$clust_dens<-renderPlot({
dd<-rval_cluster_merged_df()
ggplot(dd,aes(x=Duration, colour=Cluster, group=Cluster))+
geom_density()+ggtitle("Cluster density plot")+scale_x_log10()
})
}
最终输出将是:
我正在尝试构建一个数据分析仪表板,我正在使用 Shiny,我对它比较陌生。我的仪表板的一个功能是对用户生成的数据使用 k 均值聚类。我可以使聚类分析正常工作,但我希望能够在完成初始聚类分析后对单个聚类进行探索性数据分析。此外,我想在 Shiny 中使用反应式数据框来执行此操作,以便如果用户更改仪表板上的值,分析会刷新,包括 post- 聚类探索性内容。
首先,这是我在仪表板服务器代码和相关库中使用的一些函数,所以 运行 首先是这些:-
#libraries===================================================================
library(ids)
library(tidyverse)
library(dplyr)
library(shiny)
library(ggplot2)
library(shinydashboard)
library(shinyWidgets)
library(factoextra)
#functions required==========================================================
#scale
scale_this <- function(x){
(x - mean(x, na.rm=TRUE)) / sd(x, na.rm=TRUE)
}
#wss plot
wssplot <- function(data, nc = 15, seed = 1234) {
wss <- (nrow(data) - 1) * sum(apply(data, 2, var))
for (i in 2:nc) {
set.seed(seed)
wss[i] <- sum(kmeans(data, centers = i)$withinss)
}
plot(1:nc,
wss,
type = "b",
xlab = "Number of Clusters",
ylab = "Within groups sum of squares")
}
这里是这个例子的模拟数据框的代码:-
#Create my mock data frame============================================
set.seed(123)
randomid<-random_id(333)#from 'ids' library
Duration<-c(floor(runif(10000, min=1, max=1000)))
mockdf<-cbind(randomid, Duration)
mockdf<-as.data.frame(mockdf)
mockdf$Duration<-as.numeric(mockdf$Duration)
我的UI代码:-
#UI============================================================================
ui<-fluidPage(
titlePanel('Minimal example'),
tabsetPanel(
#=============================================kmeans clustering==================================================
tabPanel("User Type Discovery",
sidebarLayout(
sidebarPanel(width = 4,numericInput('ksolution', 'Select k solution', 5),
pickerInput('userselect', 'Which users do you want to include:',
choices = unique(mockdf$randomid), options = list('actions-box'=TRUE),multiple = T)),
mainPanel(fluidRow(
column(12, plotOutput("elbowplot")),
column(12, plotOutput("clustplot")),
column(12, plotOutput("clust_dens")),
column(12, DT::dataTableOutput('Clusterdf'))))
)
)
)
)
还有我的服务器代码:-
#SERVER===========================================================
server<-function(input,output,session){
#create reactive dataframe
rval_df <-reactive({
mockdf
})
#=============================================kmeans clustering==================================================
rval_UserData<-reactive({
rval_df()%>%
filter(randomid %in% input$userselect)%>%
group_by(randomid)%>%
summarise(Count=n(),MeanDuration=mean(Duration),SDDuration=sd(Duration))%>%
mutate(SDDuration=if_else(is.na(SDDuration),0,SDDuration),
Cluster=as.factor(rval_kclust()$cluster))
})
#create a scaled dataset for the clustering
rval_cluster_df<-reactive({
rval_df()%>%
filter(randomid %in% input$userselect)%>%
group_by(randomid)%>%
summarise(Count=n(),MeanDuration=mean(Duration),SDDuration=sd(Duration))%>%
mutate(SDDuration=if_else(is.na(SDDuration),0,SDDuration),
Count=scale_this(Count),
MeanDuration=scale_this(MeanDuration),
SDDuration=scale_this(SDDuration))%>%
select(Count,MeanDuration,SDDuration)
})
#cluster algorithm
rval_kclust<-reactive({
kmeans(rval_cluster_df(), centers = input$ksolution)
})
output$clustplot<-renderPlot({
factoextra::fviz_cluster(rval_kclust(), data = rval_cluster_df())
})
output$elbowplot<-renderPlot({
wssplot(rval_cluster_df())
})
output$Clusterdf<- DT::renderDataTable({
rval_UserData()
})
}
shinyApp(ui, server)
当您运行 shinyApp(ui,server)
时,点击应用程序下拉框中的“Select全部”按钮以运行聚类。
现在,这就是我想要做的。由于我已将簇号分配回 rval_UserData()
,我希望能够将此分配簇号合并到 mockdf
,因此我可以在 [=19] 上使用 ggplot2
生成绘图=] 变量并生成汇总表,所有这些都在集群级别。我更喜欢使用反应式数据框来做到这一点,因此绘图将根据 UI.
ksolution
输入进行刷新
这是我尝试将簇号合并回 mockdf
的一些尝试,然后尝试绘制密度图:-
rval_cluster_merged_df<-reactive({
merge(mockdf(), rval_UserData(), by="randomid")
#outside of shiny, this would be a quick way to paste the cluster number back onto the mock dataframe
})
output$clust_dens<-renderPlot({
dd<-rval_cluster_merged_df()
ggplot(dd,aes(x=Duration, colour=Cluster, group=Cluster))+
geom_density()+ggtitle("Cluster density plot")+scale_x_log10()
})
这就是我得到的,请参阅错误消息:-
很明显我做错了,但是任何正确方向的指示都将不胜感激!提前谢谢你:)
您需要对所有 input$abc
变量使用 req()
,并且 eval_tidy
因为它们不是标准变量。如下所示对您的服务器功能进行小幅更新即可解决您的问题。
server<-function(input,output,session){
#create reactive dataframe
rval_df <-reactive({
mockdf
})
#=============================================kmeans clustering==================================================
rval_UserData<-reactive({
req(input$userselect)
userselect <- eval_tidy(input$userselect)
rval_df()%>%
filter(randomid %in% userselect)%>%
group_by(randomid)%>%
summarise(Count=n(),MeanDuration=mean(Duration),SDDuration=sd(Duration))%>%
mutate(SDDuration=if_else(is.na(SDDuration),0,SDDuration),
Cluster=as.factor(rval_kclust()$cluster))
})
#create a scaled dataset for the clustering
rval_cluster_df<-reactive({
req(input$userselect)
userselect <- eval_tidy(input$userselect)
rval_df()%>%
filter(randomid %in% userselect)%>%
group_by(randomid)%>%
summarise(Count=n(),MeanDuration=mean(Duration),SDDuration=sd(Duration))%>%
mutate(SDDuration=if_else(is.na(SDDuration),0,SDDuration),
Count=scale_this(Count),
MeanDuration=scale_this(MeanDuration),
SDDuration=scale_this(SDDuration))%>%
select(Count,MeanDuration,SDDuration)
})
#cluster algorithm
rval_kclust<-reactive({
req(input$ksolution)
centers <- as.numeric(eval_tidy(input$ksolution))
kmeans(rval_cluster_df(), centers = centers)
})
output$clustplot<-renderPlot({
factoextra::fviz_cluster(rval_kclust(), data = rval_cluster_df())
})
output$elbowplot<-renderPlot({
wssplot(rval_cluster_df())
})
output$Clusterdf<- DT::renderDataTable({
rval_UserData()
})
rval_cluster_merged_df<-reactive({
merge(rval_df(), rval_UserData(), by="randomid")
})
output$clust_dens<-renderPlot({
dd<-rval_cluster_merged_df()
ggplot(dd,aes(x=Duration, colour=Cluster, group=Cluster))+
geom_density()+ggtitle("Cluster density plot")+scale_x_log10()
})
}
最终输出将是: