根据列对数据帧进行分段

时间:2012-12-06 16:10:01

标签: r

我有一个包含两列的数据框。一个用于数字,另一个用于标签 实施例

1 200 A
2 300 B
3 350 C
4 2000 A
5 2200 D
6 2300 K

我基本上想要对这个数据帧进行分段并将第二列转换为包含单词的向量,条件是第一列上的任何两个值之间的差异是< 1000

Expected Result is

C("ABC","ADK")

这里的示例我们将有一个具有ABC和ADK作为单词的向量C,因为row4和row3之间的差异> 1000

如何在不消耗大量计算的情况下做任何想法?

4 个答案:

答案 0 :(得分:3)

我没有在更大的数据集上对此进行测试,但以下情况应该有效:

df <- data.frame(Col1=c(200, 300, 350, 2000, 2200, 2300), 
                 Col2=c("A", "B", "C", "A", "D", "K"))

sapply(split(df$Col2, 
             cumsum(c(1, (diff(df$Col1) > 1000)))), 
       paste, collapse="")
#     1     2 
# "ABC" "ADK" 

在上面:

  • diff(df$Col1) > 1000会返回TRUEFALSE
  • 的向量
  • c(1, (diff(df$Col1) > 1000))将逻辑向量强制转换为数字,并添加1作为第一组的起点。因此,我们现在有一个看起来像1 0 0 1 0 0的矢量。
  • 我们现在可以在该向量上使用cumsum()来创建我们想要拆分数据的“组”。
  • sapply等已完成以粘贴Col2的相关详细信息以获取您的(已命名)向量。

答案 1 :(得分:2)

又一个答案,只是因为没有人提到你的问题是Cluster Analysis的经典案例。而且因为所有其他答案都是错误的,因为它们只是比较连续点之间的距离,因为它们应该比较所有成对距离。

可以通过hierarchical clustering并使用complete linkage来查找任意两点之间的距离小于阈值的点组。 R:

很容易
df <- data.frame(Col1 = c(200, 300, 350, 2000, 2200, 2300), 
                 Col2 = c("A", "B", "C", "A", "D", "K"))

tree <- hclust(dist(df$Col1), method = "complete")
groups <- cutree(tree, h = 1000)
# [1] 1 1 1 2 2 2
sapply(split(df$Col2, groups), paste, collapse = "")
#     1     2 
# "ABC" "ADK"

答案 2 :(得分:0)

根据您的澄清

编辑
# SAMPLE DATA
df <- data.frame(Col1=c(200, 300, 350, 2000, 2200, 2300, 4500), Col2=c("A", "B", "C", "A", "D", "K", "M"))
df

# Make sure they are the correct mode
df$Col1 <- as.numeric(as.character(df$Col1))
df$Col2 <- as.character(df$Col2)

lessThan <- which(abs(df$Col1[-length(df$Col1)] - df$Col1[-1]) > 1000 )

lapply(lessThan, function(ind)
  c( paste(df$Col2[1:ind], collapse=""),
      paste(df$Col2[ind+1:length(df$Col2)], collapse="") )
)

结果:

  [[1]]
  [1] "ABC"   "ADKM"

  [[2]]
  [1] "ABCADK" "M"    

答案 3 :(得分:0)

这是一个选项:

extractGroups <- function(data, threshold){
    #calculate which differences are greater than threshold between values in the first column
    dif <- diff(data[,1]) > threshold

    #edit: as @Ananda suggests, `cumsum` accomplishes these three lines more concisely.

    #identify where the gaps of > threshold are
    dif <- c(which(dif), nrow(data))        
    #identify the length of each of these runs
    dif <- c(dif[1], diff(dif))     
    #create groupings based on the lengths of the above runs
    groups <- inverse.rle(list(lengths=dif, values=1:length(dif)))

    #aggregate by group and paste the characters in the second column together
    aggregate(data[,2], by=list(groups), FUN=paste, collapse="")[,2]
}

关于数据的示例

extractGroups(read.table(text="1 200 A
2 300 B
3 350 C
4 2000 A
5 2200 D
6 2300 K", row.names=1), 1000)

[1] "ABC" "ADK"
相关问题