【问题标题】:Get variable combination matrix获取变量组合矩阵
【发布时间】:2020-05-24 10:22:38
【问题描述】:

数据
我们有许多看起来像这样的文本字符串(在我们的真实数据集中更长):

df <- data.frame(
  id = c('text1','text2','text3'),text = c('ABA','ABA','AAA')
)


>df
     id text
1 text1  ABA
2 text2  ABA
3 text3  AAA

我们想要创建一个矩阵来告诉我们在位置 x 的一个字母与其他位置的其他字母一起被找到的频率,所以在这种情况下:

3A  3   1   2   3
2B  2   0   2   2
2A  1   1   0   1
1A  3   1   2   3
    1A  2A  2B  3A

我尝试了什么

我之前将矩阵转换为二进制矩阵,如下所示:

structure(list(pos1_A = c(1, 1, 1), pos2_A = c(0, 0, 1), pos2_B = c(1, 
1, 0), pos3_A = c(1, 1, 1)), class = "data.frame", row.names = c("text1", 
"text2", "text3"))

      pos1_A pos2_A pos2_B pos3_A
text1      1      0      1      1
text2      1      0      1      1
text3      1      1      0      1

然后我可以运行像cor 这样的命令来获取相关性,但是,我想要频率而不是相关性。


注意这不同于关于共现的问题,其中变量名本身(此处的位置)被忽略,例如“How to use R to create a word co-occurrence matrix

【问题讨论】:

  • 我不明白您如何获得预期的输出?什么是1A3A
  • @RonakShah 第一个是位置(数字),第二个是字母,不过我愿意接受有关如何表示这一点的建议!
  • 字符串可以有多长?
  • @dvd280 它们现在是 53 个字符(大小相同)
  • @RonakShah 用您的其他答案解决了这个问题!

标签: r dataframe matrix text combinations


【解决方案1】:

感谢@Ronak Shah 的回答here


如果我们将分类数据转换为数字(二进制​​矩阵)会简单得多,例如使用homals 包的这种简单但简单的方法,然后应用上面链接的@Ronak Shah 的方法:

# The dataset
df <- data.frame(
  id = c('text1','text2','text3'),text = c('ABA','ABA','AAA')
)

# Split the strings in characters and add column names
df2 <- df %>% splitstackshape::cSplit('text', sep = '', stripWhite = FALSE, type.convert = FALSE, direction = 'wide') %>%
  column_to_rownames('id')
colnames(df2) <- paste0('pos', 1:ncol(df2))

# Convert to binary matrix (hacky way)
bin.mat <- homals:::expandFrame(df2, clean = F)

# Method by @Ronak Shah to get the frequency matrix
fun <- function(x, y) sum(bin.mat[, x] & bin.mat[, y])
n <- seq_along(bin.mat)
mat <- outer(n, n, Vectorize(fun))
dimnames(mat) <- list(names(bin.mat)[n], names(bin.mat[n]))

这会产生矩阵:

>mat
       pos1_A pos2_A pos2_B pos3_A
pos1_A      3      1      2      3
pos2_A      1      1      0      1
pos2_B      2      0      2      2
pos3_A      3      1      2      3

【讨论】:

  • 请务必告诉我们它在您的 53 字符串长数据上运行的速度,我的朋友。
  • @dvd280,二进制矩阵:4320行212列只用了2.6秒! :)
  • @dvd280 将我​​的问题中的矩阵与我的答案中的矩阵进行比较,您会发现它们已经相同。无论如何,我不能花很长时间,因为相关性分析是相似的,而且速度也很快。我已经测试过了,只用了 2.6,所以如果这正是我想要的,我不明白你试图证明的合理性
  • @dvd280 真的不明白你想要达到什么目的。我不介意将它转换为二进制矩阵,如果这给了我想要的最终结果,它只会扩展我原来的时间 4 - 讨论结束
  • 该问题最初要求的是一个非二进制矩阵,但只需要添加符合 m x mn /i> 矩阵,其中 n 是原始数据框中的行数,m 是最大字符串长度和唯一字符数的乘积。对于使用所有大写和小写字母的字符串长度为 53,这需要每行大约 1000 万次基本计算。正如我的解决方案所示,这很多,但并非不可行@dvd280
【解决方案2】:

这是一种替代方法,可以按照最初的要求生成矩阵:

# Make all strings the same length:
df$text <-  stringr::str_pad(df$text, side = "right", max(nchar(df$text)))

# Create a matrix with all letters labelled by their position:
all_vals <- apply(do.call(rbind, strsplit(df$text, "")), 1, 
                  function(x) paste0(seq_along(x), x))

# Create a vector of all possible letter / position combos
all_labs <- do.call(paste0, expand.grid(seq(max(nchar(df$text))),
                                        unique(unlist(strsplit(df$text, "")))))

# Create a function that will count all co-occurences per data frame row
f <- function(y, x) as.vector(outer(x, x, function(a, b) 1 * (a %in% y & b %in% y)))

# Create the results matrix and label it
m <- matrix(rowSums(apply(as.data.frame(all_vals), 2, f, all_labs)), nrow = length(all_labs))
rownames(m) <- all_labs
colnames(m) <- all_labs
m
#>    1A 2A 3A 1B 2B 3B
#> 1A  3  1  3  0  2  0
#> 2A  1  1  1  0  0  0
#> 3A  3  1  3  0  2  0
#> 1B  0  0  0  0  0  0
#> 2B  2  0  2  0  2  0
#> 3B  0  0  0  0  0  0

reprex package (v0.3.0) 于 2020 年 5 月 24 日创建

【讨论】:

  • 谢谢艾伦!也会试试这个
猜你喜欢
  • 2016-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-21
相关资源
最近更新 更多