Преобразование списков-столбцов в таблицы, используя в этом случае «пересечение» - PullRequest
0 голосов
/ 30 апреля 2018

Как я могу выполнять функции на символьных векторах, встроенных в столбец списка тиббла в R?

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

Например, рассмотрим этот код:

require(tidyverse)    

df <- tibble(
      x = c("one two three four", "two three four five"), 
      y = c("three four five six", "four five six seven")
    )

df.lst <- df %>% 
  mutate(x.lst = str_extract_all(x, "[:alnum:]+"),
         y.lst = str_extract_all(y, "[:alnum:]+")) %>% 
  glimpse()

# Observations: 2
# Variables: 4
# $ x     <chr> "one two three four", "two three four five"
# $ y     <chr> "three four five six", "four five six seven"
# $ x.lst <list> [<"one", "two", "three", "four">, <"two", "three", "four", "...
# $ y.lst <list> [<"three", "four", "five", "six">, <"four", "five", "six", "...

df.lst %>% 
  mutate(xy.x = intersect(x.lst, y.lst))

#    Error in mutate_impl(.data, dots) : 
 #     Column `xy.x` must be length 2 (the number of rows) or one, not 0

Я пытался использовать Reduce(intersect... безуспешно.

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

Спасибо.

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018
s=df.lst%>%
     rowwise()%>%
     mutate(xy.x=list(intersect(x.lst,y.lst)))

s$xy.x
[[1]]
[1] "three" "four" 

[[2]]
[1] "four" "five"

Вы также можете использовать group_by

df.lst%>%
    group_by_(names(df.lst))%>%
    mutate(mm=list(intersect(unlist(x.lst),unlist(y.lst))))
s1$mm
[[1]]
[1] "three" "four" 

[[2]]
[1] "four" "five"

Если вы чувствуете, что, возможно, в какой-то момент у вас может быть две строки с очень похожими величинами, тогда выполните:

 df.lst%>%
    rownames_to_column%>%
    group_by(rowname)%>%
    mutate(mm=list(intersect(unlist(x.lst),unlist(y.lst))))


Now if you do the microbench on the last one as compared to the other two:

perm
Unit: milliseconds
 expr        min         lq       mean     median         uq       max   neval
   m1 333.607625 354.065554 425.308486 374.658775  514.01087  818.6467    100
   m2 810.377360 842.860575 970.846458 878.892835 1074.33373 1329.3056    100
   m3   3.179928   3.323983   4.241713   3.799968    4.49567   20.0653    100

Таким образом, после запуска микробанда на большом наборе данных, вы увидите, что group_by намного быстрее:

0 голосов
/ 30 апреля 2018

Мы можем использовать map2 из пакета , чтобы просмотреть два списка с intersect. Результат может быть сохранен в новом столбце (в данном случае Compare).

library(tidyverse)

df.lst2 <- df.lst %>%
  mutate(Compare = map2(x.lst , y.lst, ~intersect(.x, .y)))

df.lst2$Compare
# [[1]]
# [1] "three" "four" 
# 
# [[2]]
# [1] "four" "five"

Обновление

Мы также можем использовать rowwise с mutate, как и в другом предложенном сообщении. Но для больших фреймов данных rowwise может снизить производительность функции intersect. Здесь я использовал пакет microbenchmark для оценки этих двух методов в большом фрейме данных (10000 строк) с одинаковой структурой с df.lst.

library(microbenchmark)

# Create a large data frame
df_large <- data.frame(
  ID = 1:10000,
  x = df$x,
  y = df$y,
  stringsAsFactors = FALSE
)

df_large <- df_large %>% 
  select(-ID) %>%
  as.tibble()

df_large.lst <- df_large %>%
  mutate(x.lst = str_extract_all(x, "[:alnum:]+"),
         y.lst = str_extract_all(y, "[:alnum:]+")) %>% 
  glimpse() 
# Observations: 10,000
# Variables: 4
# $ x     <chr> "one two three four", "two three four five", "one two three four", "two three...
# $ y     <chr> "three four five six", "four five six seven", "three four five six", "four fi...
# $ x.lst <list> [<"one", "two", "three", "four">, <"two", "three", "four", "five">, <"one", ...
# $ y.lst <list> [<"three", "four", "five", "six">, <"four", "five", "six", "seven">, <"three...

# Performance Evaluation
perm <- microbenchmark(
  m1 = {df_large.lst2 <- df_large.lst %>%
    mutate(xy.x = map2(x.lst , y.lst, ~intersect(.x, .y)))},
  m2 = {df_large.lst2 <- df_large.lst %>%
    rowwise() %>%
    mutate(xy.x = list(intersect(x.lst, y.lst))) %>%
    ungroup()},
  m3 = {df_large.lst2 <- df_large.lst%>%
      rownames_to_column () %>%
      group_by(rowname) %>%
      mutate(xy.x =list(intersect(unlist(x.lst),unlist(y.lst))))},
  times = 100L
)

perm
# Unit: milliseconds
# expr      min       lq     mean   median       uq      max neval
#   m1 158.8871 171.7935 183.0220 176.3373 191.0863 260.3079   100
#   m2 353.1279 387.1014 405.2522 401.6800 422.6556 459.7453   100
#   m3 436.0175 465.9106 496.4585 481.7983 527.7079 613.0461   100
...