【问题标题】:Plotting sublist parameters efficiently using a loop in R使用 R 中的循环有效地绘制子列表参数
【发布时间】:2013-12-31 06:48:38
【问题描述】:

我无法创建一个循环,我不知道出了什么问题。我的数据包含列表中的列表。我有 >50 个主要列表,即 [[i]]。每个 [[i]] 包含 20 个 `i` (=sublist)。我的数据子集看起来像

>data
[[1]]$`1`
           X       Y  Height_m kt_Result   
1   253641.0 2630050        90       560  
74  253845.7 2630552        90       270
156 254353.6 2630195       130         0
171 254554.9 2630220       170       390
173 254565.9 2630323       120       304

[[1]]$`2`
           X       Y  Height_m kt_Result   
5   253641.0 2630050        50       860  
77  253845.7 2630552        20       370
159 254353.6 2630195       190        20
177 254554.9 2630220       140       310
200 254565.9 2630323       100       804

... ...

[[2]]$`1`
           X       Y  Height_m kt_Result   
4   253641.0 2630050        10       960  
78  253845.7 2630552        20       220
150 254353.6 2630195       330         5
377 254554.9 2630220       670       340
100 254565.9 2630323       220       314

... ...

当我想在一个图中用不同颜色绘制每个子列表时,它不起作用

#blank plot (dfs is a different data frame with the same data)
plot(dfs[[1]]$kt_Result, dfs[[1]]$Height_m, type='n')

#plot sublist
lapply(1:length(data[[1]]), function(i) 
  points(data[[1]]$`i`$kt_Result, data[[1]]$`i`$Height_m,
         ylim=rev(c(0, max(data[[1]]$`i`$Height_m))),
         xlim= c(min(data[[1]]$`i`$kt_Result, na.rm=TRUE), 
max(data[[1]]$`i`$kt_Result, na.rm=TRUE)), lwd=2, type='b',col=i))

我收到没有任何情节的警告

There were 50 or more warnings (use warnings() to see the first 50)
> warnings()
Warning messages:
1: In max(data[[1]]$i$Height_m) : no non-missing arguments to max; returning -Inf
2: In min(data[[1]]$i$kt_Result, na.rm = TRUE) :
  no non-missing arguments to min; returning Inf
3: In max(data[[1]]$i$kt_Result, na.rm = TRUE) :
  no non-missing arguments to max; returning -Inf
... ...

当我在没有任何 x-/y- 限制的情况下进行绘图时,它不会给出警告或绘图,只是在工作区中显示 NULL!

lapply(1:length(data[[1]]), function(i) 
  points(data[[1]]$`i`$kt_Result, data[[1]]$`i`$Height_m,
         lwd=2, type='p',col=i))

[[1]]
NULL

[[2]]
NULL

...

[[20]]
NULL

但是,当我将数据逐个绘制时,它可以工作,但这是处理如此大的数据集的一种不切实际的方法

plot(dfs[[1]]$kt_Result, dfs[[1]]$Height_m, type='n')

points(data[[1]]$`1`$kt_Result, data[[1]]$`1`$Height_m, col='red')
points(data[[1]]$`2`$kt_Result, data[[1]]$`2`$Height_m, col='green')
... ...
points(data[[1]]$`19`$kt_Result, data[[1]]$`19`$Height_m, col='cyan')
points(data[[1]]$`20`$kt_Result, data[[1]]$`20`$Height_m, col='blue')

知道为什么这个简单的循环不起作用吗?

【问题讨论】:

  • 这可能是少数几个地方之一,for 循环在 R 中是有意义的,我会尝试的。
  • 您期望某些东西可以通过设计工作而不会起作用。 $ 从不 评估它的论点。 See this answer 了解更多信息并使用[,i] 而不是$
  • reshape2::melt(data) 会将您的数据转换为非常适合 ggplot2 或 lattice 的长格式 data.frame。
  • 用 R 基础解决此类问题的任何方法?
  • @baptiste,好主意,没有意识到 melt 可用于嵌套列表。不过,您确实需要这样做:melt(data, id.vars=c("height", "weight"))。我将在下面更新我的代码。

标签: r list loops lapply sublist


【解决方案1】:

@SimonO10 在您的代码中突出显示了问题,但除此之外,您是否考虑过 ggplot?它确实旨在轻松完成此类事情。您将遇到的主要问题是您需要将数据转换为长格式。但是一旦你完成了,绘图几乎是微不足道的:

# Use ggplot to plot

ggplot(
  subset(data, L1==1),  # just use `data` here if you want all plots
  aes(x=height, y=weight, color=paste(L1, L2, sep="-"))
) + geom_point() + scale_color_discrete(name="id-sub.id") + scale_y_reverse()

如果你想用facet_wrap 在不同的图表中显示内容(请注意数据已更改,因为我没有设置随机种子):

ggplot(
  subset(data, L1==1),  # just use `data` here if you want all plots
  aes(x=height, y=weight, color=paste(L1, L2, sep="-"))
) + geom_point() + scale_color_discrete(name="id-sub.id") +
facet_wrap( ~ L2)

为了将您的数据转换为长格式,我从您的结构中的一些数据开始(请参阅帖子末尾了解我是如何做到的):

data
# [[1]]
# [[1]]$`1`
#        height     weight
# 1  0.79199970 0.19434040
# 2  0.83137244 0.41325506
# ...
# 
# [[1]]$`2`
#         height     weight
# 1  0.099096870 0.64563244
# 2  0.736456033 0.06103266
# ...
# 
# [[2]]
# [[2]]$`1`
#       height      weight
# 1  0.2622071 0.176313366
# 2  0.5747873 0.887846513
# ...

然后按照@baptiste 的建议转换为长格式(注意数字不完全匹配 b/c 我重新生成了随机数据)

# Convert to long format

library(reshape2)
data <- melt(data, id.vars=c("height", "weight"))
#         height     weight L2 L1
# 1   0.55637070 0.50990818  1  1
# 2   0.59839293 0.91242349  1  1
# ...
# 11  0.39170638 0.86185414  2  1
# 12  0.69356092 0.03145715  2  1
# ...
# 21  0.67580737 0.55668117  1  2
# 22  0.01335459 0.29615540  1  2
# ...           

以及生成数据的代码:

data <- 
  replicate(5, simplify=F,
    replicate(2, simplify=F,
      data.frame(height=runif(10), weight=runif(10))
  ) )
data <- lapply( data, function(x) { names(x) <- seq_along(x); x } )

【讨论】:

  • 谢谢,但您绘制了所有内容(1-1、1-2、2-1、2-2 等)。您将如何仅绘制 1-1 和 1-2?抱歉,我不熟悉 ggplot。
  • 只是子集数据。不要将data 传递给ggplot,而是传递subset(data, id==1)
  • 感谢您的更新。好吧...可能是我问的太多了,但是您将如何为 id=L1 的每个子集创建一个循环?正如我所说,有超过 50 个 id,即循环将创建 >50 个图 ...
  • 如果你想让它们都同时出现,你可以使用facet_wrap(),但是如果你想要50个图可能太多了。否则,您可以将ggplot 语句放在for 循环中并将循环索引值传递给subset 表达式。我将添加一个 facet_wrap 示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-14
  • 2016-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多