0

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

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")

此处的示例将有一个向量 C,其中包含 ABC 和 ADK 作为单词,因为 row4 和 row3 之间的差异 > 1000

关于如何在不消耗大量计算的情况下做到这一点的任何想法?

4

4 回答 4

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以获取您的(命名)向量。
于 2012-12-06T16:45:02.530 回答
2

另一个答案,只是因为没有人提到您的问题是聚类分析的经典案例。并且还因为所有其他答案都是错误的,因为它们只是在比较所有成对距离时才比较连续点之间的距离。

寻找任意两点之间的距离小于阈值的点组可以通过层次聚类完全链接来处理。使用 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"
于 2012-12-06T18:37:31.413 回答
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"
于 2012-12-06T16:45:55.077 回答
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"    
于 2012-12-06T16:19:46.843 回答