在数据框上定义和应用自定义区间

35

我使用Python创建了以下包含相似度值的数据框:

  cosinFcolor cosinEdge cosinTexture histoFcolor histoEdge histoTexture    jaccard
1       0.770     0.489        0.388  0.57500000 0.5845137    0.3920000 0.00000000
2       0.067     0.496        0.912  0.13865546 0.6147309    0.6984127 0.00000000
3       0.514     0.426        0.692  0.36440678 0.4787535    0.5198413 0.05882353
4       0.102     0.430        0.739  0.11297071 0.5288008    0.5436508 0.00000000
5       0.560     0.735        0.554  0.48148148 0.8168083    0.4603175 0.00000000
6       0.029     0.302        0.558  0.08547009 0.3928234    0.4603175 0.00000000
我正在尝试编写一个R脚本生成另一个数据框来反映区间,但只有在值大于0.5时,才会应用我的分组条件。以下是伪代码:
if (cosinFcolor > 0.5 & cosinFcolor <= 0.6)
   bin = 1
if (cosinFcolor > 0.6 & cosinFcolor <= 0.7)
   bin = 2
if (cosinFcolor > 0.7 & cosinFcolor =< 0.8)
   bin = 3
if (cosinFcolor > 0.8 & cosinFcolor <=0.9)
   bin = 4
if (cosinFcolor > 0.9 & cosinFcolor <= 1.0)
   bin = 5
else
   bin = 0

基于上述逻辑,我想构建一个数据框

  cosinFcolor cosinEdge cosinTexture histoFcolor histoEdge histoTexture    jaccard
1       3         0         0            1           1        0               0

我应该怎么将这个做成一个脚本,还是应该用Python?我想在发现R有多么强大的机器学习包之后,尝试熟悉一下R。

我的目标是构建一个分类器,但首先需要熟悉R :)


2
请查看?findInterval或cut。 - mnel
对于那些愿意采用data.table方法的人,我编写了一个灵活的bin_data()方法,并在这个答案中进行了描述。 - Ben
看起来你想将完全相同的箱应用于所有7列,而不仅仅是cosinFcolor - smci
4个回答

60

另一个考虑极端情况的简略答案:

dat <- read.table("clipboard", header=TRUE)

cuts <- apply(dat, 2, cut, c(-Inf,seq(0.5, 1, 0.1), Inf), labels=0:6)
cuts[cuts=="6"] <- "0"
cuts <- as.data.frame(cuts)

  cosinFcolor cosinEdge cosinTexture histoFcolor histoEdge histoTexture jaccard
1           3         0            0           1         1            0       0
2           0         0            5           0         2            2       0
3           1         0            2           0         0            1       0
4           0         0            3           0         1            1       0
5           1         3            1           0         4            0       0
6           0         0            1           0         0            0       0

解释

cut函数根据您指定的切割点将数据分成若干个区间。因此,如果我们以1到10为例,在3、5和7处进行切割。

cut(1:10, c(3, 5, 7))
 [1] <NA>  <NA>  <NA>  (3,5] (3,5] (5,7] (5,7] <NA>  <NA>  <NA> 
Levels: (3,5] (5,7]

您可以看到它已经创造了一个因素,其中级别是在断点之间的级别。同时请注意,它不包括数字3(有一个include.lowest参数,可以将其包括在内)。但这些都是可怕的分组名称,让我们称它们为第1组和第2组。

cut(1:10, c(3, 5, 7), labels=1:2)
 [1] <NA> <NA> <NA> 1    1    2    2    <NA> <NA> <NA>
更好了,但是NA是怎么回事?它们在我们的范围之外并且不计入统计。为了将它们计入统计,在我的解决方案中,我添加了负无穷和正无穷,这样所有点都会被包括在内。请注意,随着我们有更多的断点,我们需要更多的标签:
x <- cut(1:10, c(-Inf, 3, 5, 7, Inf), labels=1:4)
 [1] 1 1 1 2 2 3 3 4 4 4
Levels: 1 2 3 4

好的,但是我们不想要4(根据你的问题)。我们希望所有的4都在第一组中。因此,让我们摆脱标记为“4”的条目。

x[x=="4"] <- "1"
 [1] 1 1 1 2 2 3 3 1 1 1
Levels: 1 2 3 4

这有点不同于我之前所做的,注意我在之前去掉了所有末尾的标签,但是我现在这样做是为了让你更好地看到cut如何工作。

好的,接下来是apply函数。到目前为止,我们一直在对单��向量使用cut。但是您希望它用于集合中的向量:即数据框的每列。这就是apply的第二个参数所做的事情。1将该函数应用于所有行,2将其应用于所有列。将cut函数应用于您数据框的每一列。在apply函数中,cut之后的所有内容都是对cut的参数进行讨论。


有没有可能解释一下你正在做的事情,我很想理解它的逻辑并真正学会它,而不仅仅是复制它。 - add-semi-colons
@Null-Hypothesis 已添加了一份解释。 - sebastian-c
如果桶不遵循精确的顺序会怎么样?如果这些是另一个数据帧中的自定义桶呢? - BlackHat
@user3116753 这个序列只是举例而已。在我的解释中,你会看到我使用了自定义分割。 - sebastian-c

26

你还可以使用findInterval函数:

findInterval(seq(0, 1, l=20), seq(0.5, 1, by=0.1))

## [1] 0 0 0 0 0 0 0 0 0 1 1 2 2 3 4 4 5 5

2
是的,这是一个非常有用的函数。它可以让你避免使用cut()函数创建混乱的因子。 - IRTFM
2
你不必使用cut()函数来得到混乱的因子。你可以将labels参数设置为False,这样就可以获得整数编码而不是因子,但是不会牺牲cut()函数所提供的灵活性。 - dsh

16

使用 cut 像吃馅饼一样容易

dtf <- read.table(
textConnection(
"cosinFcolor cosinEdge cosinTexture histoFcolor histoEdge histoTexture jaccard
1 0.770 0.489 0.388 0.57500000 0.5845137 0.3920000 0.00000000
2 0.067 0.496 0.912 0.13865546 0.6147309 0.6984127 0.00000000
3 0.514 0.426 0.692 0.36440678 0.4787535 0.5198413 0.05882353
4 0.102 0.430 0.739 0.11297071 0.5288008 0.5436508 0.00000000
5 0.560 0.735 0.554 0.48148148 0.8168083 0.4603175 0.00000000
6 0.029 0.302 0.558 0.08547009 0.3928234 0.4603175 0.00000000"), sep = " ", 
           header = TRUE)

dtf$bin <- cut(dtf$cosinFcolor, breaks = c(0, seq(0.5, 1, by = .1)), labels = 0:5)
dtf
  cosinFcolor cosinEdge cosinTexture histoFcolor histoEdge histoTexture    jaccard bin
1       0.770     0.489        0.388  0.57500000 0.5845137    0.3920000 0.00000000   3
2       0.067     0.496        0.912  0.13865546 0.6147309    0.6984127 0.00000000   0
3       0.514     0.426        0.692  0.36440678 0.4787535    0.5198413 0.05882353   1
4       0.102     0.430        0.739  0.11297071 0.5288008    0.5436508 0.00000000   0
5       0.560     0.735        0.554  0.48148148 0.8168083    0.4603175 0.00000000   1
6       0.029     0.302        0.558  0.08547009 0.3928234    0.4603175 0.00000000   0

2
这里有另一种解决方案,使用mltools包中的bin_data()函数。

对一个向量进行分箱

library(mltools)

cosinFcolor <- c(0.77, 0.067, 0.514, 0.102, 0.56, 0.029)
binned <- bin_data(cosinFcolor, bins=c(0, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0), boundaryType = "[lorc")

binned
[1] (0.7, 0.8] [0, 0.5]   (0.5, 0.6] [0, 0.5]   (0.5, 0.6] [0, 0.5]  
Levels: [0, 0.5] < (0.5, 0.6] < (0.6, 0.7] < (0.7, 0.8] < (0.8, 0.9] < (0.9, 1]

# Convert to numbers 0, 1, ...
as.integer(binned) - 1L

对数据框中的每一列进行分组

df <- read.table(textConnection(
  "cosinFcolor cosinEdge cosinTexture histoFcolor histoEdge histoTexture jaccard
0.770 0.489 0.388 0.57500000 0.5845137 0.3920000 0.00000000
0.067 0.496 0.912 0.13865546 0.6147309 0.6984127 0.00000000
0.514 0.426 0.692 0.36440678 0.4787535 0.5198413 0.05882353
0.102 0.430 0.739 0.11297071 0.5288008 0.5436508 0.00000000
0.560 0.735 0.554 0.48148148 0.8168083 0.4603175 0.00000000
0.029 0.302 0.558 0.08547009 0.3928234 0.4603175 0.00000000"
), sep = " ", header = TRUE)

for(col in colnames(df)) df[[col]] <- as.integer(bin_data(df[[col]], bins=c(0, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0), boundaryType = "[lorc")) - 1L

df
  cosinFcolor cosinEdge cosinTexture histoFcolor histoEdge histoTexture jaccard
1           3         0            0           1         1            0       0
2           0         0            5           0         2            2       0
3           1         0            2           0         0            1       0
4           0         0            3           0         1            1       0
5           1         3            1           0         4            0       0
6           0         0            1           0         0            0       0

[lorc是一个数组指示器吗?它是什么类型的? - WestCoastProjects
"lorc"代表“左开右闭”,表示每个区间的边界类型。最左侧的 "[" 表示“将最左侧的区间设为左闭合”。有关示例,请参阅?bin_data - Ben
谢谢。有没有一种方法可以针对给定的数据框,将每个数值列分成K个区间?(也许我应该把这个问题单独提出来问...) - WestCoastProjects
你是指像这样吗?df <- iris[, c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width")]; bin_data(unlist(df), bins = 5) - Ben
太棒了! - WestCoastProjects

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