我经常意识到3D图不是呈现一组数据的最有效方式,但我之前为特定数据集制作的2D图似乎表明3D图有助于打破信息进入更独特的聚类分析。话虽这么说,我在R中从未这样做过,而且在使用plot3d()制作3D散点图之前,我在重构数据框时遇到了麻烦。
目前,我的数据框有2列和几千行信息。第一列是标识符,A,B,C ......第二列是该标识符的一个测量特征。
实施例
ID Area
A 1.2
A 3.0
A 2.7
B 1.4
B 2.5
C 4.3
C 2.1
C 1.7
我将绘制Y轴上的区域。使用像table()这样的函数,我可以得到A,B或C出现的次数:(A = 3,B = 2,C = 3),这个值将成为所有ID的x坐标结果。但我想要做的是将这些信息放入第三列,为给定的x坐标分配唯一的z。换句话说,Z应表示给定X已显示的次数,并且对于特定X的每个新实例将增加1.最终,原因是特定于所有对象的区域值(y) ID在唯一的x,z坐标上彼此堆叠。这是我被困的地方。 基本上,我希望给定上述输入的最终数据帧输出如下所示:
ID(x) Area(y) Z
3 1.2 1
3 3.0 1
3 2.7 1
2 1.4 1
2 2.5 1
3 4.3 2
3 2.1 2
3 1.7 2
答案 0 :(得分:2)
我们可以通过两种方式实现这一目标。
<强> 1。基础R - 聚合/ ave
我们可以使用aggregate
来获取ID&#39;中每个元素的长度(&#39; IDx&#39;)列,通过创建&#39; Z&#39;来转换输出数据集(&#39; dfN&#39;)。基于&#39; IDx&#39;中的重复元素的列和&#39;合并&#39; &#39; dfN&#39;使用原始数据集&#39; df1&#39;
dfN <- aggregate(cbind(IDx=seq_along(ID))~ID, df1, FUN=length)
dfN$Z <- with(dfN, ave(IDx, IDx, FUN=function(x) cumsum(duplicated(x))+1L))
merge(df1, dfN, by='ID')[-1]
# Area IDx Z
#1 1.2 3 1
#2 3.0 3 1
#3 2.7 3 1
#4 1.4 2 1
#5 2.5 2 1
#6 4.3 3 2
#7 2.1 3 2
#8 1.7 3 2
<强> 2。基数R - ave / rle
我们可以创建&#39; IDx&#39;使用ave
的列,然后使用`rle / inverse.rle&#39;创造&#39; Z&#39;柱
df1$IDx <- with(df1, ave(seq_along(ID), ID, FUN=length))
v1 <- with(df1, paste0(ID, IDx))
df1$Z <- inverse.rle(within.list(rle(v1), values <-ave(lengths,
lengths, FUN=function(x) cumsum(duplicated(x))+1L)))
df1
# ID Area IDx Z
#1 A 1.2 3 1
#2 A 3.0 3 1
#3 A 2.7 3 1
#4 B 1.4 2 1
#5 B 2.5 2 1
#6 C 4.3 3 2
#7 C 2.1 3 2
#8 C 1.7 3 2
第3。 data.table 强>
转换&#39; data.frame&#39;到&#39; data.table&#39; (setDT
),创建&#39; IDx&#39;即nrows(.N
),按ID&#39;分组。根据IDx&#39;中的重复元素,我们可以创建&#39; Z&#39;柱。将密钥设置为&#39; ID&#39; (setkey
),加入&#39; df1&#39;,并将不必要的列指定为NULL(ID:= NULL
)
library(data.table)
setkey(setDT(df1)[, list(IDx=.N), by = ID][, IDx1:= IDx][,
list(ID,Z=cumsum(duplicated(IDx1))+1L) , IDx], ID)[df1][, ID := NULL][]
# IDx Z Area
#1: 3 1 1.2
#2: 3 1 3.0
#3: 3 1 2.7
#4: 2 1 1.4
#5: 2 1 2.5
#6: 3 2 4.3
#7: 3 2 2.1
#8: 3 2 1.7
<强> 4。 dplyr 强>
这个想法与上面的相似。我们使用left_join
library(dplyr)
left_join(df1,
df1 %>%
group_by(ID) %>%
summarise(IDx=n()) %>%
group_by(IDx) %>%
mutate(Z=cumsum(duplicated(IDx))+1L), by='ID') %>%
select(-ID)
# Area IDx Z
#1 1.2 3 1
#2 3.0 3 1
#3 2.7 3 1
#4 1.4 2 1
#5 2.5 2 1
#6 4.3 3 2
#7 2.1 3 2
#8 1.7 3 2
注意:使用其他数据集对此进行测试&#39; df2&#39;
df1 <- structure(list(ID = c("A", "A", "A", "B", "B", "C", "C", "C"),
Area = c(1.2, 3, 2.7, 1.4, 2.5, 4.3, 2.1, 1.7)), .Names = c("ID",
"Area"), class = "data.frame", row.names = c(NA, -8L))
df2 <- structure(list(ID = c("A", "A", "A", "B", "B", "C", "C", "C",
"D", "D", "D", "E", "E", "F"), Area = c(1.2, 3, 2.7, 1.4, 2.5,
4.3, 2.1, 1.7, 1.2, 1.4, 2.1, 1.2, 1.5, 2.3)), .Names = c("ID",
"Area"), class = "data.frame", row.names = c(NA, -14L))