在R中绘制一个区域

3

我用[-1,1]^2区间内的100个随机x-y坐标生成了一个矩阵:

n <- 100
datam <- matrix(c(rep(1,n), 2*runif(n)-1, 2*runif(n)-1), n) 
# leading 1 column needed for computation
# second column has x coordinates, third column has y coordinates

我将它们通过给定的目标函数f(一个向量)分类为两个类别-1和1。 我计算出一个假设函数g,现在想要可视化它与目标函数f的匹配程度。

f <- c(1.0, 0.5320523, 0.6918301)   # the given target function
ylist <- sign(datam %*% f)    # classify into -1 and 1

# perceptron algorithm to find g:
perceptron = function(datam, ylist) {
  w <- c(1,0,0)             # starting vector
  made.mistake = TRUE 
  while (made.mistake) {
  made.mistake=FALSE 
  for (i in 1:n) {
  if (ylist[i] != sign(t(w) %*% datam[i,])) {
    w <- w + ylist[i]*datam[i,]
    made.mistake=TRUE 
  }
 }
}
return(w=w)
}

g <- perceptron(datam, ylist)

我现在想在图中比较f和g。
在Mathematica中,这很容易实现。下面显示的是数据集和目标函数f,它将数据分为+1和-1两部分: http://i.imgur.com/hBFThsZ.png 这个Mathematica图显示了f和g的比较(不同的数据集和f): http://i.imgur.com/CeZTqoZ.png 这是相应的Mathematica代码。
ContourPlot[g.{1, x1, x2} == 0, {x1, -1, 1}, {x2, -1, 1}]

我该如何在R中做类似的事情(ggplot会很好)?

是的,这是可能的。但是您提供的示例无法重现,因此我无法用代码回答您。 - ECII
1
抱歉,我添加了一个可工作示例的代码。 - spore234
可能是在ggplot2中突出显示感兴趣的区域的重复问题。 - James
@James 我不确定这是否是一个重复问题。在我看来,OP询问的是如何从数据中获取判别边界,而不是如何在图形上产生阴影。 - ECII
3个回答

3

同样的事情使用ggplot。这个例子完全按照您的代码,然后在最后添加:

# OP's code...
# ...

glist <- sign(datam %*% g)

library(reshape2)  # for melt(...)
library(plyr)      # for .(...)
library(ggplot2)
df <- data.frame(datam,f=ylist,g=glist) # df has columns: X1, X2, X3, f, g
gg <- melt(df,id.vars=c("X1","X2","X3"),variable.name="model")

ggp <- ggplot(gg, aes(x=X2, y=X3, color=factor(value)))
ggp <- ggp + geom_point()
ggp <- ggp + geom_abline(subset=.(model=="f"),intercept=-f[1]/f[3],slope=-f[2]/f[3])
ggp <- ggp + geom_abline(subset=.(model=="g"),intercept=-g[1]/g[3],slope=-g[2]/g[3])
ggp <- ggp + facet_wrap(~model)
ggp <- ggp + scale_color_discrete(name="Mistake")
ggp <- ggp + labs(title=paste0("Comparison of Target (f) and Hypothesis (g) [n=",n,"]"))
ggp <- ggp + theme(plot.title=element_text(face="bold"))
ggp

以下是 n=200, 500 和 1000 的结果。当 n=100, g=c(1,0,0) 时,可以看到 n~500 时的 f 和 g 收敛。
如果您刚接触 ggplot,首先我们创建一个数据框 (df),其中包含基于 fg 的分类的坐标 (X2 和 X3) 和两列。然后,我们使用 melt(...) 将其转换为新数据框 gg,格式为 "long"。 gg 包含列 X1、X2、X3、model 和 value。列 gg$model 标识模型 (f 或 g)。相应的分类在 gg$value 中。然后,ggplot 呼叫执行以下操作:
  1. 建立默认数据集 gg、x 和 y 坐标以及着色 [ggplot(...)]
  2. 添加点图层 [geom_point(...)]
  3. 添加分隔分类的线条 [geom_abline(...)]
  4. 告诉 ggplot 在不同的 "facets" 中绘制两个模型 [facet_wrap(...)]
  5. 设置图例名称。
  6. 设置图表标题。
  7. 使图表标题加粗。

2

你的例子仍无法重现。看看我的代码,你会发现f和g是完全相同的。此外,你似乎正在对你没有的数据点进行线性外推(你问题的第二部分)。你有证据表明歧视应该是线性的吗?

#Data generation
n <- 10000
datam <- matrix(c(rep(1,n), 2*runif(n)-1, 2*runif(n)-1), n) 
# leading 1 column needed for computation
# second column has x coordinates, third column has y coordinates
datam.df<-data.frame(datam)
datam.df$X1<-NULL
f <- c(1.0, 0.5320523, 0.6918301)   # the given target function
f.col <- ifelse(sign(datam %*% f)==1,"darkred", "darkblue")    
f.fun<-sign(datam %*% f)

# perceptron algorithm to find g:
perceptron = function(datam, ylist) {
  w <- c(1,0,0)             # starting vector
  made.mistake = TRUE 
  while (made.mistake) {
  made.mistake=FALSE 
  for (i in 1:n) {
  if (ylist[i] != sign(t(w) %*% datam[i,])) {
    w <- w + ylist[i]*datam[i,]
    made.mistake=TRUE 
  }
 }
}
return(w=w)
}


g <- perceptron(datam, f.fun)
g.fun<-sign(datam %*% g)

绘制整体数据

plot(datam.df$X2, datam.df$X3, col=f.col, pch=".", cex=2)

输入图像描述

针对g和f函数存在问题,我会分别制作独立的图表。在你解决这个问题之后,你可以将所有东西放在一个图表中。你还可以查看并选择是否需要阴影。如果没有证据表明分类是线性的,使用 chull() 标记你所拥有的数据可能更加明智。

对于f函数

plot(datam.df$X2, datam.df$X3, col=f.col, pch=".", xlim=c(-1,-0.5), ylim=c(-1,-.5), cex=3, main="f function")
datam.df.f<-datam.df[f.fun==1,]
ch.f<-chull(datam.df.f$X2, datam.df.f$X3 )
ch.f <- rbind(x = datam.df.f[ch.f, ], datam.df.f[ch.f[1], ])
polygon(ch.f, lwd=3, col=rgb(0,0,180,alpha=50, maxColorValue=255))

在此输入图片描述

针对g函数

    g.col <- ifelse(sign(datam %*% g)==1,"darkred", "darkblue")    
    plot(datam.df$X2, datam.df$X3, col=g.col, pch=".", xlim=c(-1,-0.5), ylim=c(-1,-.5), cex=3, main="g function")
    datam.df.g<-datam.df[g.fun==1,]
    ch.g<-chull(datam.df.g$X2, datam.df.g$X3 )
    ch.g <- rbind(x = datam.df.g[ch.g, ], datam.df.g[ch.g[1], ])
    polygon(ch.g, col=rgb(0,0,180,alpha=50, maxColorValue=255), lty=3, lwd=3)

enter image description here

ch.f和ch.g对象是围绕您的点的“包”坐标。您可以提取这些点来描述您的线。


注:原文已经是英文,所以无需翻译,只需要将其翻译成中文即可。
ch.f
lm.f<-lm(c(ch.f$X3[ ch.f$X2> -0.99 & ch.f$X2< -0.65 & ch.f$X3<0 ])~c(ch.f$X2[ ch.f$X2>-0.99 & ch.f$X2< -0.65 & ch.f$X3<0]))
curve(lm.f$coefficients[1]+x*lm.f$coefficients[2], from=-1., to=-0.59, lwd=5, add=T)
lm.g<-lm(c(ch.g$X3[ ch.g$X2> -0.99 & ch.g$X2< -0.65 & ch.g$X3<0 ])~c(ch.g$X2[ ch.g$X2>-0.99 & ch.g$X2< -0.65 & ch.g$X3<0]))
curve(lm.g$coefficients[1]+x*lm.g$coefficients[2], from=-1., to=-0.59, lwd=5, add=T, lty=3)

您会得到

在此输入图片描述

不幸的是,由于您的示例中f和g函数相同,因此您无法看到上图中的不同行。


谢谢。您选择了n = 10000,这么多的训练样本f和g应该确实是相同的,至少在图中是如此。训练数据是线性可分的,因为我是这样做的:首先生成100个数据点,然后选择一个线性函数来将它们分开。第三步,将它们分类为两类,即线性函数上方和下方的类别。现在,我想使用感知算法基于分类的训练集生成(现在未知的)线性函数。 - spore234
图形看起来很好,但是我能让线条更加线性,更像abline()吗? - spore234
当然。ch.f和ch.g对象是“包”的坐标。提取所需的点,对其进行建模并投影。请参阅我的更新答案。 - ECII

1
你可以使用plot()中的col参数来指示f()函数的分类。并且你可以使用polygon()来填充你的g()函数的分类区域。如果你提供一个可重现的示例,我们可以回答具体的代码。这将产生类似于你展示的Mathematica图形的结果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接