从数据框中提取变量的第一次出现的行

62

我有一个由两个变量Date和Taxa构成的数据框,想要获取每个taxa第一次出现的日期。数据框中包含172行,9种不同的日期和40种不同的taxa,但我的答案应该只有40行。

Taxa是一个因子,Date是一个日期。

例如,我的数据框(称为'species')设置如下:

Date          Taxa
2013-07-12    A
2011-08-31    B
2012-09-06    C
2012-05-17    A
2013-07-12    C
2012-09-07    B

我希望你能提供这样的答案:

Date          Taxa
2012-05-17    A
2011-08-31    B
2012-09-06    C

我尝试使用:

t.first <-  species[unique(species$Taxa),]

它为我提供了正确的行数,但是有重复的分类。如果我只使用unique(species$Taxa),似乎可以给出正确的答案,但是我不知道它第一次出现的日期。

感谢任何帮助。

6个回答

68
t.first <- species[match(unique(species$Taxa), species$Taxa),]

这应该能给你想要的内容。 match 返回比较向量中第一个匹配项的索引,这些索引就是你所需的行。


20
为了使这个方法生效,你首先需要确保数据框按照决定“第一个”实例的列进行排序。可以使用species[with(species, order(Date)), ] 来完成排序,具体演示可以参考这里 - Serenthia

20
在下面的命令中,duplicated会为重复的data$Taxa值创建一个逻辑索引。使用以下代码创建不包含相应行的数据框子集:
data[!duplicated(data$Taxa), ]

结果:
        Date Taxa
1 2012-05-17    A
2 2011-08-31    B
3 2012-09-06    C

8
为了使这个方法生效,你必须先确保你的数据框按照决定“第一个”实例所在列进行排序。可以使用species[with(species, order(Date)), ]来完成排序,具体操作可以参考这里 - Serenthia
我有一个简单的情况,我不在乎选择哪一个 - 所以这对我来说在不排序的情况下很有效。 - Monica Heddneck
@MonicaHeddneck 如果您不关心要选择哪一个,那么顺序就无关紧要了。您可以使用这种技术。 - Sven Hohenstein
是的,先生,我们在说同样的事情! - Monica Heddneck

14

这里有一个 dplyr 选项,不依赖于数据按日期排序,并考虑了并列的情况:

library(dplyr)
df %>% 
  mutate(Date = as.Date(Date)) %>% 
  group_by(Taxa) %>% 
  filter(Date == min(Date)) %>% 
  slice(1) %>% # takes the first occurrence if there is a tie
  ungroup()

# A tibble: 3 x 2
  Date       Taxa 
  <date>     <chr>
1 2012-05-17 A    
2 2011-08-31 B    
3 2012-09-06 C 

# sample data:
df <- read.table(text = 'Date          Taxa
                         2013-07-12    A
                         2011-08-31    B
                         2012-09-06    C
                         2012-05-17    A
                         2013-07-12    C
                         2012-09-07    B', header = TRUE, stringsAsFactors = FALSE)

通过按日期排序,您也可以获得相同的结果:

df %>% 
  mutate(Date = as.Date(Date)) %>% 
  group_by(Taxa) %>% 
  arrange(Date) %>% 
  slice(1) %>% 
  ungroup()

4

以下是使用 data.table 的解决方案:

library(data.table)
setDT(species)
species[, .SD[which.min(Date)], by = Taxa]
#    Taxa       Date
# 1:    A 2012-05-17
# 2:    B 2011-08-31
# 3:    C 2012-09-06

数据:

species <- data.frame(
  Date = as.Date(c("2013-07-12", "2011-08-31", "2012-09-06", 
                   "2012-05-17", "2013-07-12", "2012-09-07")), 
  Taxa = c("A", "B", "C", "A", "C", "B")
)

2
这应该就可以解决问题了:
# Create some dummy data:

# Create some dates 
Date=as.POSIXct(c("2013-07-12","2011-08-31","2012-09-06","2009-01-01",
                  "2012-05-17","2013-07-12","2012-09-07","2013-02-02"))

# Create unique taxa
Taxa=rep(c("A","B","C","D"),2)

# Combine the two into a dataframe
data=as.data.frame(list(Date=Date,Taxa=Taxa))

# this returns a numeric vector of the minimum dates
xx=tapply(data$Date,list(data$Taxa),min)

# And this will return a dataframe with the first occurence
# of your taxa (or variables)
as.data.frame(list(Date=as.POSIXct(xx,origin="1970-01-01"),
                   Taxa=names(xx)))

注意:您可以在tapply中添加simplify=T以返回POSIXt对象,但它会返回一个列表。更多信息可以在此处找到:min、tapply和POSIXct/POSIXlt类的意外行为?

0

这是一个好问题。首先,我想强调你提到的输出不符合你的要求。应该是:

Date          Taxa
2013-07-12    A
2011-08-31    B
2012-09-06    C

也就是说,第一个条目不正确。现在谈论这个问题的代码,所有这些都是好的答案,但我提出的解决方案更加健壮。 为了更好地演示,我使用了一个新的数据框。

d <- data.frame(a = c(rep("A", 4), c(rep("B",4)), rep("C",4)), b=c(0,0,1,1,0,1,1,1,0,0,0,1))
d %>% group_by(a) %>% mutate(c = detect_index(.x = b, .f = p), d = row_number()) %>% mutate(e = ifelse(c==d,1,0)) %>% ungroup()

继续编码!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接