【问题标题】:Can I get geom_smooth() to allow line breaks when there are NA values?当有 NA 值时,我可以让 geom_smooth() 允许换行吗?
【发布时间】:2020-12-25 04:01:21
【问题描述】:

我希望找到一种在使用 geom_smooth() 时显示换行符的方法 - 这可能吗?

这是我正在使用的示例数据和代码以及结果图:

game_number <- c(1:52)

toi <- c(NA, NA, NA, NA, 20.4, 20.2, 19.4, 18.6, 17.8, 17.1, 17.7, 17.3, 16.8, 17.1, 17.8, 17.3, 16.6,
        16.9, 17.4, 16.9, 16.1, 16.6, 16.9, 16.4, NA, NA, NA, NA, NA, NA, 16.9, 18.2, 18.5, 16.6, 16.3, 15.7, 
        15.1, 14.7, 16.5, 17.9, 16.9, NA, 17.6, 18.1, 17.9, 17.2, 18.2, 18.0, 17.3, 17.8, 18.3, 17.9)

toi_df <- tibble(player = 'Nils Lundkvist', game_number = game_number, toi = toi)
plot <- ggplot(toi_df, aes(x = game_number, y = toi, group = player, colour = player)) +
            geom_line(size = 0.6) +
            geom_smooth(se = F, size = 1) +
            scale_y_continuous(limits = c(0, 25), expand = c(0, 0))

生成的图如下所示。您可以在 geom_line() 中看到 NA 换行符,但 geom_smooth() 线连接到 NA 值。在这种情况下,有没有办法让 geom_smooth() 表现得像 geom_line() ?或者使用其他一些 ggplot 命令来代替?谢谢!

【问题讨论】:

  • 这可能是一个 hack,并不适用于所有数据,但您可以创建虚拟组,然后使用这些组执行 geom_smooth() 并将它们着色为相同的颜色吗?

标签: r ggplot2 smoothing


【解决方案1】:

我会建议一种方法,您可以在独立数据框中计算 geom_smooth() 输出,然后与原始数据合并。这里使用broomtidyverse 包的方法:

library(tidyverse)
library(broom)

首先是数据:

#Data
game_number <- c(1:52)
toi <- c(NA, NA, NA, NA, 20.4, 20.2, 19.4, 18.6, 17.8, 17.1, 17.7, 17.3, 16.8, 17.1, 17.8, 17.3, 16.6,
         16.9, 17.4, 16.9, 16.1, 16.6, 16.9, 16.4, NA, NA, NA, NA, NA, NA, 16.9, 18.2, 18.5, 16.6, 16.3, 15.7, 
         15.1, 14.7, 16.5, 17.9, 16.9, NA, 17.6, 18.1, 17.9, 17.2, 18.2, 18.0, 17.3, 17.8, 18.3, 17.9)
toi_df <- tibble(player = 'Nils Lundkvist', game_number = game_number, toi = toi)

现在,我们计算平滑模型:

#Create smooth
model <- loess(toi ~ game_number, data = toi_df)

我们创建一个数据框来保存结果:

#Augment model output in a new dataframe
toi_df2 <- augment(model, toi_df)

我们合并数据:

#Merge data
toi_df3 <- merge(toi_df,
                 toi_df2[,c("player","game_number",".fitted")],
                 by=c("player","game_number"),all.x = T)

最后,我们使用geom_line()进行绘图:

#Plot
ggplot(toi_df3, aes(x = game_number, y = toi, group = player, colour = player)) +
  geom_line(size = 0.6) +
  geom_line(aes(y=.fitted),size=1) +
  scale_y_continuous(limits = c(0, 25), expand = c(0, 0))

输出:

如果您有多个玩家,该方法可能会奏效。在这种情况下,您可以按玩家分组(group_by() 来自dplyr)并使用do() 函数来估计每个玩家的平滑模型。

更新:

我为多人游戏添加了代码。在这种情况下,我创建了一个函数来遍历列表中玩家定义的组。创建函数后,您必须使用split() 来获取每个玩家的列表。函数myfunsmooth() 计算loess。然后,绑定数据并绘制绘图。代码如下:

虚拟数据:

#Data
game_number <- c(1:52)
toi <- c(NA, NA, NA, NA, 20.4, 20.2, 19.4, 18.6, 17.8, 17.1, 17.7, 17.3, 16.8, 17.1, 17.8, 17.3, 16.6,
         16.9, 17.4, 16.9, 16.1, 16.6, 16.9, 16.4, NA, NA, NA, NA, NA, NA, 16.9, 18.2, 18.5, 16.6, 16.3, 15.7, 
         15.1, 14.7, 16.5, 17.9, 16.9, NA, 17.6, 18.1, 17.9, 17.2, 18.2, 18.0, 17.3, 17.8, 18.3, 17.9)
toi_df <- tibble(player = 'Nils Lundkvist', game_number = game_number, toi = toi)
toi_df0 <- tibble(player = 'Zach Ellenthal', game_number = game_number, toi = toi)
toi_df0$toi <- toi_df0$toi+15 
toi_dfm <- rbind(toi_df,toi_df0)

loess()的函数:

#Function for smoothing
myfunsmooth <- function(x)
{
  #Model
  model <- loess(toi ~ game_number, data = x)
  #Augment model output in a new dataframe
  y <- augment(model, x)
  #Merge data
  z <- merge(x,y[,c("player","game_number",".fitted")],
                   by=c("player","game_number"),all.x = T)
  #Return
  return(z)
}

然后,我们创建列表:

#Create list by player
List <- split(toi_dfm,toi_dfm$player)

我们应用函数并将结果绑定到一个新的数据框中:

#Apply function
List2 <- lapply(List, myfunsmooth)
#Bind all
dfglobal <- do.call(rbind,List2)
rownames(dfglobal)<-NULL

最后,我们绘制:

#Plot
ggplot(dfglobal, aes(x = game_number, y = toi, group = player, colour = player)) +
  geom_line(size = 0.6) +
  geom_line(aes(y=.fitted),size=1) +
  scale_y_continuous(limits = c(0, 45), expand = c(0, 0)) 

输出:

【讨论】:

  • 谢谢,这看起来真的很不错,很高兴尝试一下。我第一次尝试的两个问题。首先,分配toi_df2 时出现错误,上面写着Error: Assigned data predict(x, na.action = na.pass, ...) %&gt;% unname() must be compatible with existing data. 还说现有数据有52 行,分配的数据有41 行。知道为什么这对我来说不同吗?其次,我将有多个玩家,那么我将在流程中的哪个位置/哪个变量中使用group_by()?谢谢!
  • @ZachEllenthal 嗨 Zach,您的问题可能是因为与其他软件包发生冲突。尝试开始一个新的会话并加载broom。如果有多个玩家,我现在会更新帖子。
  • @ZachEllenthal 我为多人游戏添加了更新。请检查。希望对你有帮助:)
  • 非常感谢您的帮助!仍然试图通过broom::augment 中的错误消息,甚至打开一个新会话并仅加载tidyversebroom。但如果我能克服这一点,我想我可以理解你提出的解决方案的其余部分。
  • @ZachEllenthal 那么,您在运行代码时遇到了问题,仅使用这篇文章中的数据,还是您使用的是其他数据?
猜你喜欢
  • 2019-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-17
  • 2016-11-21
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
相关资源
最近更新 更多