在R中,如何访问因子的每个级别的第一个元素?

时间:2014-03-19 22:15:17

标签: r r-factor

我有一个这样的数据框:

n = c(2, 2, 3, 3, 4, 4) 
n <- as.factor(n)
s = c("a", "b", "c", "d", "e", "f") 
df = data.frame(n, s)  

df
  n s
1 2 a
2 2 b
3 3 c
4 3 d
5 4 e
6 4 f

我希望访问我的每个级别的第一个元素(在这个例子中包含a, c, e的矢量)。

可以使用

到达一个级别的第一个元素
df$s[df$n == 2][1]

但它并不适用于所有级别:

df$s[df$n == levels(n)]
[1] a f

你会怎么做?

为了更进一步,我想修改我的数据框,看看哪个是每次出现的每个级别的第一个元素。在我的示例中,新列应为:

  n s rep firstelement
1 2 a   a            a
2 2 b   c            a
3 3 c   e            c
4 3 d   a            c
5 4 e   c            e
6 4 f   e            e

7 个答案:

答案 0 :(得分:16)

修改即可。我的答案的第一部分解决了原始的问题,即之前“并且更进一步”(在编辑中由OP添加)。

使用duplicated的另一种可能性。从?duplicated:“duplicated()确定向量或数据框的哪些元素与具有较小下标的元素重复。”

这里我们使用!,逻辑否定(NOT)来选择'n'的重复元素,即每个'n'级别的第一个元素。

df[!duplicated(df$n), ]
#   n s
# 1 2 a
# 3 3 c
# 5 4 e

更新直到现在才看到您的“并进一步”编辑。我的第一个建议肯定是使用ave,正如@thelatemail和@sparrow已经提出的那样。但只是在R工具箱中挖掘并向您展示另一种选择,这里是dplyr方式:

n对数据进行分组,使用mutate函数创建一个新的变量'first',其值为's的第一个元素'(s[1]),

library(dplyr)

df %.%
  group_by(n) %.%
  mutate(
    first = s[1])
#   n s first
# 1 2 a     a
# 2 2 b     a
# 3 3 c     c
# 4 3 d     c
# 5 4 e     e
# 6 4 f     e

或全面使用dplyr便捷功能并使用first代替[1]

df %.%
  group_by(n) %.%
  mutate(
    first = first(s))

原始问题的dplyr解决方案是使用summarise

df %.%
  group_by(n) %.%
  summarise(
    first = first(s))

#   n first
# 1 2     a
# 2 3     c
# 3 4     e

答案 1 :(得分:11)

以下是使用match的方法:

 df$s[match(levels(n), df$n)]

编辑:也许这看起来有点令人困惑......

要获取列出第一个元素的列,您可以使用match两次(但交换xtable个参数):

 df$firstelement <- df$s[match(levels(n), df$n)[match(df$n, levels(n))]]
 df$firstelement
 # [1] a a c c e e
 # Levels: a b c d e f

让我们详细看一下:

 ## this returns the first matching elements
 match(levels(n), df$n)
 # [1] 1 3 5

 ## when we swap the x and table argument in match we get the level index
 ## for each df$n (the duplicated indices are important)
 match(df$n, levels(n))
 # [1] 1 1 2 2 3 3

 ## results in
 c(1, 3, 5)[c(1, 1, 2, 2, 3, 3)]
 # [1] 1 1 3 3 5 5
 df$s[c(1, 1, 3, 3, 5, 5)]
 # [1] a a c c e e
 # Levels: a b c d e f

答案 2 :(得分:6)

函数ave在这些情况下很有用:

df$firstelement = ave(df$s, df$n, FUN = function(x) x[1])
df
  n s firstelement
1 2 a            a
2 2 b            a
3 3 c            c
4 3 d            c
5 4 e            e
6 4 f            e

答案 3 :(得分:4)

在这种情况下,我更喜欢plyr包,它可以进一步自由地操纵数据。

library(plyr)
ddply(df,.(n),function(subdf){return(subdf[1,])})

  n s
1 2 a
2 3 c
3 4 e

答案 4 :(得分:4)

您也可以使用data.table

library(data.table)
dt = as.data.table(df)
dt[, list(firstelement = s[1]), by=n]

哪能得到你:

   n firstelement
1: 2            a
2: 3            c
3: 4            e

by=n位按n的每个值对所有内容进行分组,因此s[1]获取每个组的第一个元素。

要将此作为额外的列,您可以这样做:

dt[, newcol := s[1], by=n]
dt
#   n s newcol
#1: 2 a      a
#2: 2 b      a
#3: 3 c      c
#4: 3 d      c
#5: 4 e      e
#6: 4 f      e

所以这只是从每个组的第一行获取s的值并将其分配给新列。

答案 5 :(得分:2)

df$s[sapply(levels(n), function(particular.level) { which(df$n == particular.level)[1]})]

我相信你的问题是你正在比较两个向量df $ n是一个向量而level(n)是一个向量。 vector == vector恰好适合你,因为df $ n是level(n)的倍数长度

答案 6 :(得分:0)

感到惊讶的是还没有在答案流中看到这个经典。

> do.call(rbind, lapply(split(df, df$n), function(x) x[1,]))
##   n s
## 2 2 a
## 3 3 c
## 4 4 e