Cria uma matriz de documento de termo a partir de arquivos

2

Eu tenho um conjunto de arquivos de example001.txt a example100.txt . Cada arquivo contém uma lista de palavras-chave de um superconjunto (o superconjunto está disponível se quisermos).

Então example001.txt pode conter

apple
banana
...
otherfruit

Gostaria de poder processar esses arquivos e produzir algo parecido com uma matriz, de modo que haja a lista de examples* na linha superior, a fruta na lateral e '1' em uma coluna, se a fruta está no arquivo.

Um exemplo pode ser ...

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

Alguma ideia de como eu poderia construir algum tipo de mágica de linha de comando para juntar isso? Estou no OSX e feliz com perl ou python ...

    
por Joe 01.12.2012 / 15:45

4 respostas

4

Com o Python, você pode instalar o textmining até

sudo pip install textmining

Em seguida, crie um novo arquivo - vamos chamá-lo de matrix.py e adicione o seguinte:

#!/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)

Salve e chame chmod +x matrix.py . Agora, basta executá-lo com ./matrix.py . Este programa irá procurar no diretório especificado em glob() e escrever a matriz de saída para matrix.csv em seu diretório atual, talvez assim:

Comovocêpodever,aúnicadesvantageméqueelenãoexibeosnomesdosdocumentos.Podemosprefixaressalista,usandoalgunscomandosbash-sóprecisamosdeumalistadosnomesdosarquivos:

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

E, cole isso junto com o matrix.csv :

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

Voilà, nossa matriz completa de documentos de termo:

Eu posso imaginar que existem soluções menos complicadas, mas isso é Python e eu não o conheço bem o suficiente para alterar o código para produzir toda a matriz correta.

    
por 01.12.2012 / 22:32
2

É quase a solução slhck. Acabei de adicionar dentro do script Python os comandos bash executados via os.sytem, para colocar tudo em um script python sem necessidade de alternar entre o console python e 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 """)
    
por 31.10.2013 / 16:39
1

Eu não posso dar a você algo tão bonito quanto a solução python do slhck, mas aqui está uma pura 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

Se você copiar / colar aquela coisa horrível em um terminal, supondo que sua lista de frutas esteja em um arquivo chamado superset.txt com uma fruta por linha, você verá:

        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              

EXPLICAÇÃO:

  • printf "\t" : imprime uma TAB para que os nomes dos arquivos estejam alinhados ao final dos nomes das frutas.
  • for file in ex*; [...] done : imprime os nomes dos arquivos (supondo que sejam os únicos arquivos cujo nome começa com ex .
  • echo "" : imprima uma nova linha
  • while read fruit; do [...]; done <list : list deve ser um arquivo de texto contendo o superconjunto mencionado, ou seja, todas as frutas, uma fruta por linha. Este arquivo é lido neste loop e cada fruta é salva como $fruit .
  • printf "$fruit\t"; : imprime o nome da fruta e uma TAB.
  • for file in ex*; do [...]; done : Aqui nós passamos por cada arquivo novamente e usamos grep -wc $fruit $file para obter o número de vezes que a fruta que estamos processando atualmente foi encontrada naquele arquivo.

Você também pode usar column mas eu nunca tentei:

 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.

E aqui está um Perl. Tecnicamente, este é um forro, ainda que LONGO:

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*

Aqui está na forma de script comentada que pode ser inteligível:

#!/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
} 

Isso tem o benefício de lidar com "frutas" arbitrárias, não é necessário superconjunto. Além disso, essas duas soluções usam ferramentas * nix nativas e não exigem a instalação de pacotes adicionais. Dito isso, a solução python na resposta do slhck é mais concisa e dá uma saída mais bonita.

    
por 01.04.2013 / 18:53
0

Em Python, você pode usar sklearn.feature_extraction.text.CountVectorizer.fit_transform : aprende o dicionário de vocabulário e retorna uma matriz de documentos de termo .

Exemplo:

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_))

saídas:

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}

Como você está trabalhando com arquivos, talvez esteja interessado no método sklearn.feature_extraction.text.CountVectorizer.transform() também.

    
por 25.08.2015 / 03:33