Определение и применение пользовательских бинов к фрейму данных

Используя 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

Как я могу запустить это как скрипт или мне нужно сделать это на питоне? Я пытаюсь познакомиться с R после того, как узнал, насколько он мощный/количество пакетов машинного обучения, которые у него есть. Моя цель - создать классификатор, но сначала мне нужно познакомиться с R :)


person add-semi-colons    schedule 15.08.2012    source источник
comment
Посмотрите на ?findInterval или cut   -  person mnel    schedule 15.08.2012
comment
Для тех, кто готов к data.table подходу, я написал гибкий bin_data(), который я описал в этом ответе.   -  person Ben    schedule 18.09.2016
comment
Похоже, вы хотите применить одни и те же ячейки ко всем 7 столбцам, а не только к cosinFcolor   -  person smci    schedule 16.09.2018


Ответы (4)


Еще один сокращенный ответ, учитывающий экстремумы:

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

Объяснение

Функция вырезания разбивается на бины в зависимости от указанных вами разрезов. Итак, давайте возьмем 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 были в группе 1. Итак, давайте избавимся от записей с пометкой «4».

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

Это немного отличается от того, что я делал раньше, обратите внимание, что я удалил все последние метки в конце, но здесь я сделал это так, чтобы вы могли лучше видеть, как работает cut.

Хорошо, функция apply. До сих пор мы использовали разрез на одном векторе. Но вы хотите, чтобы он использовался для набора векторов: каждого столбца вашего фрейма данных. Это то, что делает второй аргумент apply. 1 применяет функцию ко всем строкам, 2 применяется ко всем столбцам. Примените функцию cut к каждому столбцу вашего фрейма данных. Все, что находится после cut в функции применения, является просто аргументами для cut, о чем мы говорили выше.

Надеюсь, это поможет.

person sebastian-c    schedule 15.08.2012
comment
При любой возможности вы могли бы объяснить, что вы делаете, я хотел бы понять логику и действительно изучить ее, а не просто справляться с ней. - person add-semi-colons; 15.08.2012
comment
@Null-Hypothesis Добавлено объяснение. - person sebastian-c; 16.08.2012
comment
Что делать, если ведра не следуют точной последовательности? Что, если это пользовательские сегменты в другом фрейме данных? - person BlackHat; 19.05.2015
comment
@user3116753 user3116753 Последовательность была просто для примера. В моем объяснении вы увидите, что я использовал пользовательские разделения. - person sebastian-c; 10.08.2015

Вы также можете использовать 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
person mnel    schedule 15.08.2012
comment
Да. Очень полезная функция. Позволяет избежать создания беспорядочных факторов с помощью cut(). - person IRTFM; 31.08.2012
comment
Вы не должны иметь грязный фактор с сокращением. Вы можете установить labels = False, чтобы получить целые коды, а не множители, но без ущерба для гибкости, которую предоставляет вам функция cut(). - person dsh; 28.04.2017

С разрезом все просто

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
person Luciano Selzer    schedule 15.08.2012

Вот еще одно решение с использованием функции bin_data() из пакета mltools.

Бинирование одного вектора

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

Бинирование каждого столбца в data.frame

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
person Ben    schedule 13.07.2017
comment
является ли [lorc индикатором массива? какого типа? - person WestCoastProjects; 28.01.2018
comment
lorc означает лево-открыто-право-закрыто, указывая на тип границы каждой ячейки. [ в крайнем левом углу означает, что самая левая корзина закрыта слева. См. ?bin_data несколько примеров. - person Ben; 28.01.2018
comment
спасибо. есть ли способ просто сказать для данного фрейма данных: разбить каждый столбец с числовым значением на K ячеек? (может быть, я должен задать это как отдельный вопрос ..) - person WestCoastProjects; 28.01.2018
comment
Вы имеете в виду вот так? df <- iris[, c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width")]; bin_data(unlist(df), bins = 5) - person Ben; 28.01.2018
comment
это потрясающе! - person WestCoastProjects; 28.01.2018