0

numpy 配列に大きなテキスト データを読み込もうとしています。Numpy の loadtxt と genfromtxt は as では機能しませんでした。

  • まず、区切り記号で始まるコメント行を削除する必要があります['#','!','C']
  • 2 番目に、は整数の繰り返し回数で、は float データn*valueであるという形式のデータに繰り返しパターンがあります。nvalue

したがって、 を使用してテキスト ファイルを読み取ろうとしreadlines()、Numpyを使用loadtxtしてデータを Numpy 配列に変換します。

読み取りと置換のために、正規表現 (reモジュール) を使用しようとしましたが、機能しませんでした。ただし、次の Python コードは機能しています。私の質問は、これを行う最も効率的で Pythonic な方法は何ですか?

readlines()正規表現の場合、次のリスト オブジェクトの検索と置換の正しい正規表現コードは何ですか:

lines = ['1 2 3*2.5 3 6 1*.3 8 \n', '! comment here\n', '1*1 2.0 2*2.1 3 6 0 8 \n']
for l, line in enumerate(lines):
    if line.strip() == '' or line.strip()[0] in ['#','!','C']:
        del lines[l]        
for l, line in enumerate(lines):
    repls = [word  for word in line.strip().split() if word.find('*')>=0]
    print repls
    for repl in repls:
        print repl
        line = line.replace(repl, ' '.join([repl.split('*')[1] for n in xrange(int(repl.split('*')[0]))]))
    lines[l] = line
print lines

出力は次のとおりです。

['1 2 2.5 2.5 2.5 3 6 .3 8 \n', '1 2.0 2.1 2.1 3 6 0 8 \n']

編集:

コメントに応じて、Python コードを次のように編集しました。

    in_lines = ['1 2 3*2.5 3 6 1*.3 8 \n', '! comment here\n', '1*1 2.0 2*2.1 3 6 0 8 \n']
    lines = []
    for line in in_lines:
        if line.strip() == '' or line.strip()[0] in ['#','!','C']:
            continue        
        else:
            repls = [word  for word in line.strip().split() if word.find('*')>=0]
            for repl in repls:
                line = line.replace(repl, ' '.join([float(repl.split('*')[1]) for n in xrange(int(repl.split('*')[0]))]))
            lines.append(line)
    print lines
4

1 に答える 1

1

パイソン的な方法

代わりに、Python の優れた関数型機能とリスト内包表記を使用してください。

#!/usr/bin/env python

lines = ['1 2 3*2.5 3 6 1*.3 8 \n', '! comment here\n', '1*1 2.0 2*2.1 3 6 0 8 \n']

#filter out comments
lines = [line for line in lines if  line.strip() != '' and line.strip()[0] not in ['#','!','C']]

#turns lines into lists of tokens
lines = [[word for word in line.strip().split()] for line in lines]

# turns a list of strings into a number generator, parsing '*' properly
def generate_numbers(tokens):
  for token in tokens:
    if '*' in token:
      n,m = token.split("*")
      for i in range(int(n)):
        yield float(m)
    else:
      yield float(token)

# use the generator to clean up the lines
lines = [list(generate_numbers(tokens)) for tokens in lines]

print lines

出力:

➤ ./try.py 
[[1.0, 2.0, 2.5, 2.5, 2.5, 3.0, 6.0, 0.3, 8.0], [1.0, 2.0, 2.1, 2.1, 3.0, 6.0, 0.0, 8.0]]

高速で小さな Pythonic の方法

このソリューションでは、ファイル全体をメモリにロードする必要がないように、リストの代わりにジェネレータを使用します。2 つのイディオムの使用に注意してください。

  1. with open("name") as file

    これにより、ブロックを終了した後にファイル ハンドルがクリーンアップされます。

  2. for line in file

    これにより、ファイル全体をメモリにロードすることなく、ジェネレーターを使用してファイル内の行を反復処理します。

これにより、次のことがわかります。

#!/usr/bin/env python

# turns a list of strings into a number generator, parsing '*' properly
def generate_numbers(tokens):
  for token in tokens:
    if '*' in token:
      n,m = token.split("*")
      for i in range(int(n)):
        yield float(m)
    else:
      yield float(token)

# Pull this out to make the code more readable
def not_comment(line):
  return line.strip() != '' and line.strip()[0] not in ['#','!','C']

with open("try.dat") as file:
  lines = ( 
    list(generate_numbers((word for word in line.strip().split()))) 
    for line in file if not_comment(line)
  ) # lines is a lazy generator

  for line in lines:
    print line

出力:

➤ ./try.py 
[1.0, 2.0, 2.5, 2.5, 2.5, 3.0, 6.0, 0.3, 8.0]
[1.0, 2.0, 2.1, 2.1, 3.0, 6.0, 0.0, 8.0]
于 2013-04-09T14:43:06.223 に答える