Упорядочение кадра данных по его подсегментам - PullRequest
0 голосов
/ 23 мая 2018

Моя команда и я имеем дело со многими тысячами URL-адресов, имеющих похожие сегменты.Некоторые URL имеют один сегмент («seg», множественное число, «segs») в интересующей нас позиции.Другие похожие URL имеют другой сегмент в интересующей нас позиции.Нам нужно отсортировать фрейм данных, состоящий из URL-адресов и связанных уникальных сегментов, в позиции интереса, показывая частоту этих уникальных сегментов.

Вот упрощенный пример:

 url <- c(1, 3, 1, 4, 2, 3, 1, 3, 3, 3, 3, 2)
 seg <- c("a", "c", "a", "d", "b", "c", "a", "x", "x", "y", "c", "b")
 df <- data.frame(url,seg)

Мыищу следующее:

url freq seg 
 1   3    a   in other words, url #1 appears three times each with a seg = "a",
 2   2    b   in other words: url #2 appears twice each with a seg = "b",
 3   3    c   in other words: url #3 appears three times with a seg = "c", 
 3   2    x                                  two times with a seg = "x", and, 
 3   1    y                                  once with a seg = "y"
 4   1    d   etc.

Я могу добраться туда, используя цикл и несколько небольших шагов, но я убежден, что есть более элегантный способ сделать это.Вот мой неуместный подход:

Создание пустого фрейма данных со строками num.unique и тремя столбцами (url, freq, seg)

 result <- data.frame(url=0, Freq=0, seg=0)

Определение уникальных URL-адресов

 unique.df.url <- unique(df$url)

Цикл по фрейму данных

 for (xx in unique.df.url) {
   url.seg <- df[which(df$url == unique.df.url[xx]), ] # create a dataframe for each of the unique urls and associated segs
   freq.df.url <- data.frame(table(url.seg))  # summarize the frequency distribution of the segs by url
   result <- rbind(result,freq.df.url)  # append a new data.frame onto the last one
 }

Исключение строк в фрейме данных, где частота = 0

 result.freq <- result[which(result$Freq |0), ]

Сортировка фрейма данных по URL

 result.order <- result.freq[order(result.freq$url), ]

Это дает желаемыйрезультаты, но, поскольку это настолько не элегантно, я обеспокоен тем, что, как только мы перейдем к масштабу, требуемое время будет чрезмерным или, по крайней мере, проблемой.Какие-либо предложения?

Ответы [ 5 ]

0 голосов
/ 24 мая 2018

В базе R вы можете сделать это:

aggregate(freq~seg+url,`$<-`(df,freq,1),sum)
# or aggregate(freq~seg+url, data.frame(df,freq=1),sum)

#   seg url freq
# 1   a   1    3
# 2   b   2    2
# 3   c   3    3
# 4   x   3    2
# 5   y   3    1
# 6   d   4    1

Хитрость с $<- состоит в том, чтобы просто добавить столбец freq значения 1 везде без изменения исходной таблицы.

Другая возможность:

subset(as.data.frame(table(df[2:1])),Freq!=0)
#    seg url Freq
# 1    a   1    3
# 8    b   2    2
# 15   c   3    3
# 17   x   3    2
# 18   y   3    1
# 22   d   4    1

Здесь я использую [2:1], чтобы изменить порядок столбцов, чтобы table упорядочил результаты требуемым образом.

0 голосов
/ 24 мая 2018

Или вставьте и нанесите:

url <- c(1, 3, 1, 4, 2, 3, 1, 3, 3, 3, 3, 2)
seg <- c("a", "c", "a", "d", "b", "c", "a", "x", "x", "y", "c", "b")
df <- data.frame(url,seg)

want <- tapply(url, INDEX = paste(url, seg, sep = "_"), length)
want <- data.frame(do.call(rbind, strsplit(names(want), "_")), want)
colnames(want) <- c("url", "seg", "freq")
want <- want[order(want$url, -want$freq), ]
rownames(want) <- NULL # needed?
want <- want[ , c("url", "freq", "seg")] # needed?
want
0 голосов
/ 23 мая 2018

Будет ли следующий код лучше для вас?

library(dplyr)
df %>% group_by(url, seg) %>% summarise(n()) 
0 голосов
/ 23 мая 2018
url <- c(1, 3, 1, 4, 2, 3, 1, 3, 3, 3, 3, 2)
seg <- c("a", "c", "a", "d", "b", "c", "a", "x", "x", "y", "c", "b")
df <- data.frame(url,seg)

library(dplyr)

df %>% count(url, seg) %>% arrange(url, desc(n))

# # A tibble: 6 x 3
#     url seg       n
#   <dbl> <fct> <int>
# 1     1 a         3
# 2     2 b         2
# 3     3 c         3
# 4     3 x         2
# 5     3 y         1
# 6     4 d         1
0 голосов
/ 23 мая 2018

Можно использовать table и tidyr::gather для получения данных в формате, необходимом для OP:

library(tidyverse)
table(df) %>% as.data.frame() %>% 
  filter(Freq > 0 ) %>%
  arrange(url, desc(Freq))


#   url seg  Freq
# 1   1   a     3
# 2   2   b     2
# 3   3   c     3
# 4   3   x     2
# 5   3   y     1
# 6   4   d     1

ИЛИ

df %>% group_by(url, seg) %>%
  summarise(freq = n()) %>%
  arrange(url, desc(freq))

# # A tibble: 6 x 3
# # Groups: url [4]
#    url seg      freq
#   <dbl> <fctr> <int>
# 1  1.00 a          3
# 2  2.00 b          2
# 3  3.00 c          3
# 4  3.00 x          2
# 5  3.00 y          1
# 6  4.00 d          1
...