Mon équipe et moi traitons plusieurs milliers d'URL qui ont des segments similaires. Certaines URL ont un segment ("seg", pluriel, "segs") dans une position qui nous intéresse. D'autres URL similaires ont un segment différent dans la position qui nous intéresse. Nous devons trier une trame de données composée d'URL et de segments uniques associés dans la position d'intérêt, en indiquant la fréquence de ces segments uniques.

Voici un exemple simplifié:

 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)

Nous recherchons les éléments suivants:

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.

Je peux y arriver en utilisant une boucle et plusieurs petits pas, mais je suis convaincu qu'il existe une manière plus élégante de le faire. Voici mon approche inélégante:

Créer un dataframe vide avec num.unique lignes et trois colonnes (url, freq, seg)

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

Déterminez les URL uniques

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

Boucle à travers le dataframe

 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
 }

Élimine les lignes dans la trame de données où Fréquence = 0

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

Trier le dataframe par URL

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

Cela donne les résultats escomptés, mais comme c'est tellement inélégant, je crains qu'une fois que nous passerons à l'échelle, le temps requis sera prohibitif ou du moins préoccupant. Aucune suggestion?

4
W Barker 23 mai 2018 à 19:01

5 réponses

Meilleure réponse

Dans la base R, vous pouvez faire ceci:

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

L'astuce avec $<- est simplement d'ajouter une colonne freq de valeur 1 partout, sans changer votre table source.

Une autre possibilité:

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

Ici, j'utilise [2:1] pour changer l'ordre des colonnes afin que table classe les résultats de la manière requise.

2
Moody_Mudskipper 29 mai 2018 à 23:10

Une option peut être d'utiliser table et tidyr::gather pour obtenir les données au format requis par 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

OU

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
0
MKR 25 mai 2018 à 22:02
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
AntoniosK 23 mai 2018 à 16:22

Le code suivant serait-il meilleur pour vous?

library(dplyr)
df %>% group_by(url, seg) %>% summarise(n()) 
0
Pavel Paltsev 23 mai 2018 à 16:24

Ou coller et tapoter:

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
r.user.05apr 24 mai 2018 à 08:52