您如何根据数据列之一中的因素为散点图中的点着色?

How do you color points in a scatterplot by factors in one of the data's columns?

我正在研究 R Projects for dummies,其中一页有一个使用 UCI 虹膜数据集的散点图矩阵。矩阵中的点根据虹膜的种类不同而着色。书上给出的代码是:

iris.uci <- read.csv(url("http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"),
                     header=FALSE, col.names =c("sepal.length", "sepal.width", "petal.length", "petal.width","species")  )

iris.uci[35,4] = 0.2
iris.uci[38,2:3]= c(3.6, 1.4)

iris.uci$species <- mapvalues(iris.uci$species, from = c("Iris-setosa", "Iris-versicolor", "Iris-virginica"), to = c("setosa", "versicolor", "verginica"))

pairs(iris.uci[,1:4], lower.panel=NULL, cex=2, pch=21, cex.labels =2, 
      bg = c("black", "grey", "white")[iris.uci$species])
par(xpd=NA)
legend("bottomleft", inset=c(-.5,0), legend=c("setosa", "versicolor", "verginica"), pch=21, pt.bg=c("black", "grey", "white"),
       pt.cex =2, y.intersp=1, cex=1.5, bty="n" )

对于矩阵,这只绘制了白色圆圈,尽管图例代码确实绘制了正确的颜色。我错过了什么?

如果您阅读 ?pairs,它也给出了一个 pairs(.) 图作为示例。在该示例中,它使用

     pairs(iris[1:4], main = "Anderson's Iris Data -- 3 species",
           pch = 21, bg = c("red", "green3", "blue")[unclass(iris$Species)])

这看起来和你的很相似。您可能会尝试将 unclass(.) 添加到您自己的数据中,但它不起作用。为什么?因为使用默认基数 R iris(似乎不需要下载你的 UCI 版本,顺便说一句),“物种”是一个 factor,所以在内部它被存储为一个整数和基于它引用的字符串.

str(iris)
# 'data.frame': 150 obs. of  5 variables:
#  $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#  $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#  $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#  $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#  $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...

str(iris.uci)
# 'data.frame': 150 obs. of  5 variables:
#  $ sepal.length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#  $ sepal.width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#  $ petal.length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#  $ petal.width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#  $ species     : chr  "setosa" "setosa" "setosa" "setosa" ...

但是 ...几个R版本之前,read.csv改变了它的默认行为stringsAsFactors=TRUE (已经存在了几十年?)到 stringsAsFactors=FALSE,所以你得到简单的字符串。如果您查看要传递给 bg= 的内容,您会发现它很无趣:

head( c("black", "grey", "white")[iris.uci$species] )
# [1] NA NA NA NA NA NA
table( c("black", "grey", "white")[iris.uci$species], useNA = "always" )
# <NA> 
#  150 

那是因为您正在根据字符串对三种颜色的索引进行索引,并且由于您的向量未命名,因此它什么也找不到,returns NA 查找所有内容。

有两种方法可以解决这个问题:

  1. 命名你的颜色:

    pairs(iris.uci[,1:4], lower.panel=NULL, cex=2, pch=21,
          bg = c(setosa="black", versicolor="grey", verginica="white")[iris.uci$species])
    

    这样做的好处是您可以严格控制每个物种的颜色。

  2. factor 然后 unclass:

    pairs(iris.uci[,1:4], lower.panel=NULL, cex=2, pch=21,\
          bg = c("black", "grey", "white")[unclass(factor(iris.uci$species))])
    

    (请注意,我在选项 1 中分配的物种顺序与此处显示的不同;这是故意的,以强调这样做实际上会减少一些功能。有一些方法可以使用 factors 和仍然控制颜色,但我发现选项 1 的显式颜色分配更清晰。)

(仅供参考,在原始 iris 数据集和 iris.uci 下载中,拼写为 virginica。)