【问题标题】:Subsetting data into different tables from one table with condition将数据从一个有条件的表中子集到不同的表中
【发布时间】:2017-08-23 16:57:13
【问题描述】:

我正在使用 R 对几种产品进行交叉销售分析。 我已经转换了事务数据,它看起来像这样 -

  df.articles <- cbind.data.frame(Art01,Art02,Art03)

  Art01         Art02      Art03
  bread         yoghurt    egg
  butter        bread      yoghurt
  cheese        butter     bread
  egg           cheese     NA
  potato        NA         NA

 Actual data is 'data.frame': 69099 obs. of  33 variables.

我想获得与文章一起出售的所有不同文章及其计数的列表(在这种情况下例如面包或酸奶) 实际数据包含 56 篇文章,我需要检查与它一起销售的所有文章交叉销售。所以我想要的结果必须看起来像 -

     Products sold with **bread**           Products sold with **Yoghurt**  

     yoghurt         2                        bread   2
     egg             1                        egg     1
     cheese          1                       butter   1
     butter          1          

     .... and list goes on like this for say 52 different articles. 

我已经尝试了几件事,但对于这个大数据集来说太手动了。 在 library(data.table) 的帮助下解决这个问题会很棒,如果没有,那也很好。 非常感谢您提前。

【问题讨论】:

  • 考虑将数据重新格式化为具有两列结构的 data.frame,例如 data.frame(article=c(...), ingredients = c(...))。我认为您当前的 data.frame 效率很低
  • 欢迎来到 StackOverflow!请阅读有关how to ask a good question 的信息以及如何提供reproducible example。这将使其他人更容易帮助您。

标签: r dplyr data.table


【解决方案1】:

有……

library(data.table)
setDT(DF)
dat = setorder(melt(DF[, r := .I], id="r", na.rm=TRUE)[, !"variable"])
res = dat[, CJ(art = value, other_art = value), by=r][art != other_art, .N, keyby=.(art, other_art)]

        art other_art N
 1:   bread    butter 2
 2:   bread    cheese 1
 3:   bread       egg 1
 4:   bread   yoghurt 2
 5:  butter     bread 2
 6:  butter    cheese 1
 7:  butter   yoghurt 1
 8:  cheese     bread 1
 9:  cheese    butter 1
10:  cheese       egg 1
11:     egg     bread 1
12:     egg    cheese 1
13:     egg   yoghurt 1
14: yoghurt     bread 2
15: yoghurt    butter 1
16: yoghurt       egg 1

评论。 OP 提到有 56 个不同的项目,这意味着单个订单(上面的r)在CJ 之后可能有多达 3136 = 56^2 行。对于几千个订单,这很快就会成为问题。这在进行组合计算时很常见,因此希望此任务仅用于浏览数据而不是分析数据。

浏览时的另一个想法是使用splitlapply 来自定义显示:

library(magrittr)
split(res, by="art", keep.by = FALSE) %>% lapply(. %$% setNames(N, other_art))

$bread
 butter  cheese     egg yoghurt 
      2       1       1       2 

$butter
  bread  cheese yoghurt 
      2       1       1 

$cheese
 bread butter    egg 
     1      1      1 

$egg
  bread  cheese yoghurt 
      1       1       1 

$yoghurt
 bread butter    egg 
     2      1      1 

不过,正如@ycw 在评论中建议的那样,我通常只使用res[art == "bread"]res[art == "bread" &amp; other_art == "butter"] 等进行探索。

这里并不需要 Magrittr。它只是允许不同的语法。

【讨论】:

  • 我喜欢这个数据框输出。过滤数据框以查看每个文章组合的计数(N)将很容易。
  • @ycw 谢谢。还有 split(res, by="art", keep.by = FALSE) %&gt;% lapply(. %$% setNames(N, other_art)) 和 magrittr 来格式化输出。
  • @Frank : 非常感谢 :) 这非常有效。我没有足够的语言来感谢你!
【解决方案2】:

这是一个选项。我们可以使用tidyverse 中的一些函数来创建一个包含结果的列表。 a_list4 是最终输出。每个元素都是一篇带有相关文章数量的文章。

# Prepare the data frame "dt"
dt <- read.table(text = "Art01         Art02      Art03
  bread         yoghurt    egg
                 butter        bread      yoghurt
                 cheese        butter     bread
                 egg           cheese     NA
                 potato        NA         NA",
                 header = TRUE, stringsAsFactors = FALSE)

# Load package
library(tidyverse)

# A vector with articles
articles <- unique(unlist(dt))

# Remove NA
articles <- articles[!is.na(articles)]

# A function to filter the data frame by articles
filter_fun <- function(article, dt){
  dt2 <- dt %>% filter(rowSums(. == article) > 0)
  return(dt2)
}

# Apply the filter_fun
a_list <- map(articles, filter_fun, dt = dt)
names(a_list) <- articles

# Get articles in each element of the list
a_list2 <- map(a_list, function(dt) unlist(dt))

# Remove the articles based on the name of that article
a_list3 <- map2(a_list2, names(a_list2), function(vec, article){
  vec[!(vec %in% article)]
})

# Count the number
a_list4 <- map(a_list3, table)

# See the results
a_list4

$bread

 butter  cheese     egg yoghurt 
      2       1       1       2 

$butter

  bread  cheese yoghurt 
      2       1       1 

$cheese

 bread butter 
     1      1 

$egg

  bread yoghurt 
      1       1 

$potato
< table of extent 0 >

$yoghurt

 bread butter    egg 
     2      1      1 

【讨论】:

  • 与我的方法相比,这有好处,即使它没有配对,也包括一个土豆条目。
  • @Frank 感谢分享您创建列表并比较不同方法的方法!
  • @ycw :谢谢你分享这个。我肯定会探索“tidyverse”库。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2019-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多