在一个大型数据框架中,我正在尝试根据另一个因素的标识创建一个新行,该行根据其他行对特定数据进行分组。以下是一些示例数据:
> Species Status Value
> A Introduced 10
> A Native 3
> B Crypt 6
> C Introduced 19
> C Native 4
对于每个物种,我想创建一个新行,它只获取Status“Introduced”或“Crypt”的数据,并忽略“Native”状态中的数据。每个物种的数据都只有“引入”和“原生”或只有“地穴”。
因此,我想要的输出将如下所示:
> Species Status Value
> A Introduced 10
> A Native 3
> A IC.Total 10
> B Crypt 6
> B IC.Total 6
> C Introduced 19
> C Native 4
> C IC.Total 19
for循环是最好的解决方法,还是有更优雅的方式?任何建议都会很棒 - 谢谢你的帮助!
答案 0 :(得分:2)
以下使用data.table
包
假设您的原始data.frame被称为myDat
:
library(data.table)
myDT <- data.table(myDat, key="Species")
# Creates a new DT, of only the Speices column
myDT2 <- setkey(unique(myDT[, list(Species)]), "Species")
# Add IC.Total values
myDT2[myDT[Status=="Introduced"], c("Status", "ValueC") := list("IC.Total", Value)]
# Add Crypt values
myDT2[myDT[Status=="Crypt"], c("Status", "ValueC") := list("Crypt", Value)]
# fix the column name
setnames(myDT2, "ValueC", "Value")
# combine and sort by speicies
myDT <- setkey(rbind(myDT, myDT2), "Species")
myDT
# Species Status Value
# 1: A Introduced 10
# 2: A Native 3
# 3: A IC.Total 10
# 4: B Crypt 6
# 5: B Crypt 6
# 6: C Introduced 19
# 7: C Native 4
# 8: C IC.Total 19
注意,如果您不想复制crypt
计数,只需取出上面的那一行即可。
答案 1 :(得分:1)
您可以使用merge
和aggregate
(即使没有要聚合的内容):
merge(mydf,
cbind(aggregate(Value ~ Species, mydf, sum,
subset = c(Status != "Native")),
Status = "IC.Total"),
all = TRUE)
# Species Status Value
# 1 A Introduced 10
# 2 A Native 3
# 3 A IC.Total 10
# 4 B Crypt 6
# 5 B IC.Total 6
# 6 C Introduced 19
# 7 C Native 4
# 8 C IC.Total 19
我使用了aggregate
因为它有一个方便的参数,可以让您对数据进行子集化。在这种情况下,我们对“Native”不感兴趣。此外,我们知道我们永远不会为一个物种“引入”和“地穴”,我们知道“引入”或“地穴”永远不会有多个值,所以使用sum
作为我们的聚合函数不会改变任何东西。
这个解决方案背后的概念即使你有多个“价值”变量也可以使用,正如你在评论中指出的那样,但需要做一些细微的修改,如下所示。
首先,让我们编写一些数据:
mydf <- data.frame(
Species = c("A", "A", "B", "C", "C"),
Status = c("Introduced", "Native", "Crypt", "Introduced", "Native"),
Value1 = c(10, 3, 6, 19, 4),
Value2 = c(6, 8, 12, 19, 5),
Value3 = c(18, 19, 14, 13, 2))
mydf
# Species Status Value1 Value2 Value3
# 1 A Introduced 10 6 18
# 2 A Native 3 8 19
# 3 B Crypt 6 12 14
# 4 C Introduced 19 19 13
# 5 C Native 4 5 2
其次,像以前一样使用aggregate
和merge
,但请注意细微差别。首先,我们不能像以前那样使用subset
,所以不是聚合整个数据集,而是仅聚合我们感兴趣的行。其次,我们将“状态”添加为分组变量,它不会对您的结果产生任何影响,与您描述的数据当前结构有关。第三,在我们聚合之后,我们需要删除“状态”列并添加一个新状态列(这就是[-2]
代码正在执行的操作 - 删除第二列。)
在这里,一个整齐的包装:
merge(mydf,
cbind(aggregate(. ~ Species + Status,
mydf[mydf$Status != "Native", ], sum)[-2],
Status = "IC.Total"),
all = TRUE)
# Species Status Value1 Value2 Value3
# 1 A Introduced 10 6 18
# 2 A Native 3 8 19
# 3 A IC.Total 10 6 18
# 4 B Crypt 6 12 14
# 5 B IC.Total 6 12 14
# 6 C Introduced 19 19 13
# 7 C Native 4 5 2
# 8 C IC.Total 19 19 13