在 R 中重构 3D 图的数据框
Restructuring a data frame for 3D plots in R
我经常意识到 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) 并且这个值将成为所有的 x 坐标具有该结果的 ID。但我想做的是将该信息也放入第三列,为给定的 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
我们可以通过几种方式做到这一点。
1.基础 R - aggregate/ave
我们可以使用aggregate
获取'ID'列中每个元素('IDx')的长度,通过创建'Z' 列基于 'IDx' 和 'merge' 中的重复元素 'dfN' 与原始数据集 'df1'
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
我们可以使用 ave
创建 'IDx' 列,然后使用 `rle/inverse.rle' 创建 'Z' 列
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
将 'data.frame' 转换为 'data.table' (setDT
),创建 'IDx' 即 nrows (.N
),按 [=55= 分组].基于 'IDx' 中的重复元素,我们可以创建 'Z' 列。设置key为'ID'(setkey
),join与'df1',将不需要的列赋值给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
而不是 'merge'
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
注意: 用另一个数据集测试了这个 'df2'
数据
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))
我经常意识到 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) 并且这个值将成为所有的 x 坐标具有该结果的 ID。但我想做的是将该信息也放入第三列,为给定的 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
我们可以通过几种方式做到这一点。
1.基础 R - aggregate/ave
我们可以使用aggregate
获取'ID'列中每个元素('IDx')的长度,通过创建'Z' 列基于 'IDx' 和 'merge' 中的重复元素 'dfN' 与原始数据集 'df1'
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
我们可以使用 ave
创建 'IDx' 列,然后使用 `rle/inverse.rle' 创建 'Z' 列
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
将 'data.frame' 转换为 'data.table' (setDT
),创建 'IDx' 即 nrows (.N
),按 [=55= 分组].基于 'IDx' 中的重复元素,我们可以创建 'Z' 列。设置key为'ID'(setkey
),join与'df1',将不需要的列赋值给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
注意: 用另一个数据集测试了这个 'df2'
数据
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))