从文件创建术语文档矩阵

从文件创建术语文档矩阵

我有一组文件,从example001.txtexample100.txt。每个文件都包含来自超集的关键字列表(如果需要,可以使用超集)。

因此example001.txt可能包含

apple
banana
...
otherfruit

我希望能够处理这些文件并生成类似于矩阵的东西,这样examples*在顶行有一个列表,在侧面有一个水果列表,如果文件中有水果,则在一列中显示“1”。

一个例子可能是...

x           example1    example2   example3
Apple         1            1          0
Babana        0            1          0
Coconut       0            1          1

知道如何构建某种命令行魔法来将它们组合在一起吗?我在 OSX 上,对 perl 或 python 很满意...

答案1

使用 Python,您可以textmining通过

sudo pip install textmining

然后,创建一个新文件 – 我们将其命名为matrix.py,并添加以下内容:

#!/usr/bin/env python
import textmining
import glob

tdm = textmining.TermDocumentMatrix()

files = glob.glob("/Users/foo/files/*.txt")
print(files)
for f in files:
  content = open(f).read()
  content = content.replace('\n', ' ')
  tdm.add_doc(content)
tdm.write_csv('matrix.csv', cutoff=1)

保存并调用chmod +x matrix.py。现在,只需使用运行它./matrix.py。该程序将在指定的目录中搜索glob()并将输出矩阵写入matrix.csv当前目录中,可能如下所示:

如您所见,唯一的缺点是它不输出文档名称。不过,我们可以使用几个 bash 命令将此列表添加到前面 - 我们只需要文件名列表:

echo "" > files.txt; find /Users/foo/files/ -type f -iname "*.txt" >> files.txt

然后,将其与以下内容粘贴在一起matrix.csv

paste -d , files.txt matrix.csv > matrix2.csv 

这就是我们完整的术语-文档矩阵:

我可以想象有不太复杂的解决方案,但这是 Python,我对它不够了解,无法更改代码来输出整个正确的矩阵。

答案2

这几乎是 slhck 解决方案。我只是在 Python 脚本中添加了通过 os.sytem 执行的 bash 命令,将所有内容放在一个 Python 脚本中,而无需在 Python 和 Bash 控制台之间切换。

#!/usr/bin/env python
import textmining
import glob
import os
tdm = textmining.TermDocumentMatrix()
files = glob.glob("/Users/andi/Desktop/python_nltk/dane/*.txt")
os.system("""echo "" > files.txt; find /Users/andi/Desktop/python_nltk/dane -type f -iname "*.txt" >> files.txt""")
print(files)
for f in files:
  content = open(f).read()
  content = content.replace('\n', ' ')
  tdm.add_doc(content)
tdm.write_csv('matrix.csv', cutoff=1)

os.system("""paste -d , files.txt matrix.csv > matrix2.csv """)

答案3

我无法给你提供像 slhck 的 python 解决方案那样漂亮的解决方案,但这里有一个纯 bash 解决方案:

printf "\t" && 
for file in ex*; do \
  printf "%-15s" "$file "; 
done &&
echo "" && 
while read fruit; do \
    printf "$fruit\t";
    for file in ex*; do \
      printf "%-15s" `grep -wc $fruit $file`;  
    done;  
echo ""; 
done < superset.txt

如果你将这个可怕的东西复制/粘贴到终端中,假设你的水果列表位于一个名为的文件中,superset.txt每行一个水果,你会得到:

        example1       example2       example3       
apple   1              2              2              
banana  1              1              2              
mango   0              1              1              
orange  1              1              2              
pear    0              1              1              
plum    0              0              1              

解释:

  • printf "\t":打印 TAB 以使文件名与水果名称的末尾对齐。
  • for file in ex*; [...] done:打印文件名(假设它们是唯一以 . 开头的文件)ex
  • echo "":打印新行
  • while read fruit; do [...]; done <listlist必须是包含您提到的超集(即所有水果,每行一个水果)的文本文件。此文件在此循环中读取,并将每个水果保存为$fruit
  • printf "$fruit\t";:打印水果名称和TAB。
  • for file in ex*; do [...]; done:在这里我们再次遍历每个文件并获取grep -wc $fruit $file我们当前正在处理的水果在该文件中找到的次数。

您也可以使用column但我从来没有所以没有尝试:

 The column utility formats its input into multiple columns.
 Rows are filled before columns.  Input is taken from file oper‐
 ands, or, by default, from the standard input.  Empty lines are
 ignored unless the -e option is used.

下面是一个 Perl 代码。从技术上讲,这是一行代码,尽管很长:

perl -e 'foreach $file (@ARGV){open(F,"$file"); while(<F>){chomp; $fruits{$_}{$file}++}} print "\t";foreach(sort @ARGV){printf("%-15s",$_)}; print "\n"; foreach $fruit (sort keys(%fruits)){print "$fruit\t"; do {$fruits{$fruit}{$_}||=0; printf("%-15s",$fruits{$fruit}{$_})} for @ARGV; print "\n";}' ex*

以下是带注释的脚本形式,可能更容易理解:

#!/usr/bin/env perl
foreach $file (@ARGV){ ## cycle through the files
    open(F,"$file");
    while(<F>){
    chomp;## remove newlines
    ## Count the fruit. This is a hash of hashes
    ## where the fruit is the first key and the file
    ## the second. For each fruit then, we will end up
    ## with something like this: $fruits{apple}{example1}=1
    $fruits{$_}{$file}++; 
    }
}
print "\t"; ## pretty formatting

## Print each of the file names
foreach(sort @ARGV){
    printf("%-15s",$_)
}
print "\n";  ## pretty formatting

## Now, cycle through each of the "fruit" we 
## found when reading the files and print its
## count in each file.
foreach $fruit (sort keys(%fruits)){
    print "$fruit\t"; ## print the fruit names
    do {
        $fruits{$fruit}{$_}||=0; ## Count should be 0 if none were found
        printf("%-15s",$fruits{$fruit}{$_}) ## print the value for each fruit
    } for @ARGV;
    print "\n"; ## pretty formatting
} 

这样做的好处是可以处理任意的“水果”,而不需要超集。此外,这两种解决方案都使用本机 *nix 工具,不需要安装其他软件包。也就是说,slhck 答案中的 python 解决方案更简洁,输出更漂亮。

答案4

在 Python 中,你可以使用sklearn.feature_extraction.text.CountVectorizer.fit_transform:它学习词汇词典并返回词条文档矩阵

例子:

import sklearn
import sklearn.feature_extraction

vectorizer = sklearn.feature_extraction.text.CountVectorizer(min_df=1)

corpus = ['This is the first document.',
        'This is the second second document.',
        'And the third one.',
        'Is this the first document? This is right.',]

X = vectorizer.fit_transform(corpus).toarray()
print('X: {0}'.format(X))
print('vectorizer.vocabulary_: {0}'.format(vectorizer.vocabulary_))

输出:

X: [[0 1 1 1 0 0 0 1 0 1]
    [0 1 0 1 0 0 2 1 0 1]
    [1 0 0 0 1 0 0 1 1 0]
    [0 1 1 2 0 1 0 1 0 2]]

vectorizer.vocabulary_: {u'and': 0, u'right': 5, u'third': 8, u'this': 9, u'is': 3,
                         u'one': 4, u'second': 6, u'the': 7, u'document': 1, u'first': 2}

由于您正在处理文件,您可能对以下方法感兴趣sklearn.feature_extraction.text.CountVectorizer.transform()也一样。

相关内容