【问题标题】:How to keep a row and delete others if conditions are met满足条件如何保留一行并删除其他行
【发布时间】:2018-09-14 09:51:28
【问题描述】:

我正在处理分类数据,并已将我的数据进行到最后第二步,然后才能以图形方式显示它。但是,我需要行来匹配条件,这就是我卡住的地方 - 卡住了,因为我不想手动操作。
我的数据:

x <- data.frame("Phylum" = c("Chordata", "Chordata", "Chordata", "Chordata", "Chordata", "Chordata"),
                "Class" = c("NA", "Actinopterygii", "Actinopterygii", "Actinopterygii", "Actinopterygii", "Actinopterygii"),
                "Order" = c("NA", "NA", "Gadiformes", "Gadiformes", "Gadiformes", "Gadiformes"), 
                "Family" = c("NA", "NA", "NA", "Moridae", "Moridae", "Moridae"), 
                "Genus" = c("NA", "NA", "NA", "NA", "Notophycis", "Notophycis"), 
                "Species" = c("NA", "NA", "NA", "NA", "NA", "Notophycis marginata"),
                 Number = c(21616, 12123, 1497, 730,730,730))


想要的最终结果:

y <- data.frame("Phylum" = c("Chordata", "Chordata", "Chordata", "Chordata"), 
                "Class" = c("NA", "Actinopterygii", "Actinopterygii", "Actinopterygii"), 
                "Order" = c("NA", "NA", "Gadiformes", "Gadiformes"), "Family" = c("NA", "NA", "NA", "Moridae"), 
                "Genus" = c("NA", "NA", "NA", "Notophycis"), "Species" = c("NA", "NA", "NA", "Notophycis marginata"), 
                 Number = c(9493, 10626, 767, 730))

这是一个来自更大更复杂数据集的简单子集示例。因此,如果我能以某种方式将其放入代码中:

  • 数字总和 (Phylum == "P1" &amp; Class == "NA") - 数字总和 (Class == "C1" &amp; Order == "NA") 如果门匹配,这将等于 P1 的新数字
  • 数字之和 (Class == "C1" &amp; Order== "NA") - 数字之和 (Order == "O1" &amp; Family == "NA") 如果类匹配,这将 等于 C1 的新号码等...

但是如果 Number 与多行匹配,我需要有代码来评估这些行并选择 NA 数量最少的行并保留该 Number...

我想我想编写一个函数来执行此操作,但不知道从哪里开始!

感谢帮助:)

更新

测试人员:

Phylum  Class   Order   Family  Genus   Species Reads_sum
Chordata    Elasmobranchii  Carcharhiniformes   NA  NA  NA  31
Chordata    Actinopterygii  Perciformes Scombridae  NA  NA  589
Chordata    Elasmobranchii  Carcharhiniformes   Pentanchidae    NA  NA  31
Chordata    Actinopterygii  Myctophiformes  Myctophidae Notoscopelus    NA  208
Chordata    Actinopterygii  Perciformes Scombridae  Katsuwonus  NA  589
Chordata    Actinopterygii  Myctophiformes  Myctophidae Notoscopelus    Notoscopelus caudispinosus  178
Chordata    Actinopterygii  Perciformes Scombridae  Katsuwonus  Katsuwonus pelamis  589
Cnidaria    Hydrozoa    Leptothecata    Plumulariidae   NA  NA  69
Cnidaria    Hydrozoa    Leptothecata    Plumulariidae   Plumularia  NA  69
Echinodermata   Ophiuroidea NA  NA  NA  NA  146
Echinodermata   Ophiuroidea Ophiurida   NA  NA  NA  137
Echinodermata   Ophiuroidea Ophiurida   Ophiuridae  NA  NA  137
Echinodermata   Ophiuroidea Ophiurida   Ophiuridae  Ophioplinthus   NA  137
Echinodermata   Ophiuroidea Ophiurida   Ophiuridae  Ophioplinthus   Ophioplinthus accomodata    137
Mollusca    Cephalopoda Oegopsida   Ommastrephidae  NA  NA  34311
Ochrophyta  Phaeophyceae    Ectocarpales    Acinetosporaceae    NA  NA  29

执行我想要的但每次都必须更改变量的代码:

Tester$Reads_sum[Tester$Class == "Ophiuroidea" & Tester$Order == "NA"] - sum(Tester$Reads_sum[Tester$Class == "Ophiuroidea" & Tester$Order != "NA" & Tester$Family == "NA"])

所以我希望这样的事情会起作用,我只需要将 Class 更改为其他选定的分类等级:

for (i in unique(Tester$Class)){
  Tester$Test.1 <- ifelse(Tester$Class != "NA" & Tester$Order == "NA", 
                           Tester$Reads_sum[Tester$Class == i & Tester$Order == "NA"] - sum(Tester$Reads_sum[Tester$Class == i & Tester$Order != "NA" & Tester$Family == "NA"]), 0)
  }

但它给了我一个 NA 而不是 9。

最终数据应如下所示:

Phylum  Class   Order   Family  Genus   Species Reads_sum
Chordata    Elasmobranchii  Carcharhiniformes   Pentanchidae    NA  NA  31
Chordata    Actinopterygii  Myctophiformes  Myctophidae Notoscopelus    NA  30
Chordata    Actinopterygii  Myctophiformes  Myctophidae Notoscopelus    Notoscopelus caudispinosus  178
Chordata    Actinopterygii  Perciformes Scombridae  Katsuwonus  Katsuwonus pelamis  589
Cnidaria    Hydrozoa    Leptothecata    Plumulariidae   Plumularia  NA  69
Echinodermata   Ophiuroidea NA  NA  NA  NA  9
Echinodermata   Ophiuroidea Ophiurida   Ophiuridae  Ophioplinthus   Ophioplinthus accomodata    137
Mollusca    Cephalopoda Oegopsida   Ommastrephidae  NA  NA  34311
Ochrophyta  Phaeophyceae    Ectocarpales    Acinetosporaceae    NA  NA  29

【问题讨论】:

  • 您提供的数据集中没有P1、C1、O1。
  • 这些只是占位符,试图解释我想要用整个数据集实现的目标,而不仅仅是我在这里给出的子集,而是在这个例子中 P1 = Chordata, C1 = Actinopterygii, O1 = Gadiformes等等……
  • 阅读您提供的逻辑,我觉得这并不容易。您是否找到了一种为单个简化案例手动编码的方法,我们可以看看吗?为什么输出中的数字变化如此之大?如果对未子集的行存在依赖关系,则使用数据集的简化版本而不是子集通常更容易
  • @Jonny 数字会发生变化,因为每一行都是该级别分类分辨率的总和,因此为了找出保持在较差分类分辨率下的数字,较高的分类分辨率必须从较贫穷的人中扣除。所以我找到了一个潜在的解决方案,但它不是 100% 有效,我将更新我的帖子,您可以获得数据集的简化版本和上面的潜在代码解决方案。
  • 谢谢@AvdR,我在下面发布了一个解决方案,让我知道你的进展情况

标签: r function loops for-loop split


【解决方案1】:

感谢您的更新。我想出了一些我认为符合您要求的东西,但需要一些支持。

我认为它是按c("Phylum", "Class", "Order", "Family", "Genus", "Species") 顺序排列的树状数据是否正确?并且您有兴趣为树的每个级别查找,您想删除下面层的值吗?

我希望我的代码不会太混乱,我发现以当前格式使用数据具有挑战性。我更喜欢将它分成树的各个级别,即只有 Phylum 数据的那些,一直到具有树所有级别的那些。为此,我最喜欢使用 data.table 包。

我尽可能使用lapply's,因为我发现一旦你经常使用它们就很容易理解它们。我确信会有更有效的解决方案,但作为初学者,我认为了解和理解所需的步骤更为重要。

# using data.table package, as I find it quicker and easier to work with 
# for complex problems. Run the hashed out command below if you dont have it
# install.packages("data.table")
library(data.table)

# turning in to a data.table, similar to data.frame, but some differences.
dt <- as.data.table(Tester)
# I am making an id, which I will use to split up this data. Different rows 
# have different structures, as its a tree structure, so I am going to break
# the data up
dt[, id := 1:.N]

# to do so i need to know the order of significance of the tree. I believe
# they go in this order:
col_structure <- c("Phylum", "Class", "Order", "Family", "Genus", "Species")

# I want to find out at which level of the tree each row is, so I am going
# to change teh shape from wide to long, and then do some row aggregation on 
# the single column, to group
melt_dt <- melt(dt, id.vars = "id", 
                measure.vars = col_structure)
# tip: try not to use "NA", but instead NA, they have different structures 
# and built in commands like is.na make them easier to differentiate
melt_dt[value == "NA", value := NA]
melt_dt <- melt_dt[!is.na(value)]
melt_dt[]
# using a data.table command .N, grouped by id, to find out how many non NA
# values there are, this will tell me where it is in the tree
group_ids <- melt_dt[, .N, by = id]

# Ok, so now I will split up each row in to where it sits in the tree
split_ids <- split(group_ids, group_ids$N)
split_ids
# pull out the number of levels of tree for easy use
levels <- seq_along(split_ids)

# merge back in the original data, so we have the same data at the start, but
# split up in to new sets. Makes it easier to think about the problem
split_dt <- lapply(levels, function(x){
  out <- merge(split_ids[[x]], dt, by = "id")
  N <- as.numeric(names(split_ids)[x])
  # using keys in my data, to make easy extraction. means rather than do
  # Phylum == "a" & Class == "b" later on, if Phylum & Class are the keys,
  # then can use command J("a", "b"). See next stage
  setkeyv(out, col_structure[1:N])
  out
})

# Now I'm going to add the value in. I will look at the next level of the tree
# and remove the values from that level from the reads_sum. Try it with setting
# x = 1.
# I've removed bottom element of the tree, don't know what to do with them
split_dt_with_value <- lapply(levels[1:(length(levels)-1)], function(x){
  # similar to for loop, but using data.table keys to extract data
  out <- split_dt[[x]]
  out$Test.1 <- out$Reads_sum - sapply(1:nrow(out), function(i){
    sum(split_dt[[(x+1)]][J(out[i, key(out), with = FALSE])]$Reads_sum,
        na.rm = TRUE)
  })
  out
})

# combine results, and with the bottom tree level
combined <- rbindlist(c(split_dt_with_value,
                        split_dt[max(levels)]), 
                        fill = TRUE)
# turn it back in to data frame form 
combined <- as.data.frame(combined)
combined

请看一下,如果有任何步骤令人困惑,或者任何逻辑不正确,请告诉我:)

干杯,乔尼

【讨论】:

  • 这太棒了,对我拥有的所有其他 df 来说就像一个魅力 - 感谢您的分步解释,非常清楚!
  • 谢谢你,很高兴能帮上忙 :)
猜你喜欢
  • 2023-02-17
  • 2021-12-17
  • 2021-06-06
  • 2017-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多