Удалить строки, у которых определенный атрибут меньше или равен 0

У меня есть несколько больших текстовых файлов (30 м + строки, >1 ГБ), которые обрабатываются в ArcGIS после разделения (см. Удаление отдельных строк из большого текстового файла в python и разбиение текстовой базы данных на N равных блоков и сохранение заголовка для фона).

Даже после разделения процесс занимает более 3 дней, поэтому я хочу удалить все точки xy, у которых значение (Rx) меньше или равно 0.

У меня нет Python для работы над чтением наборов данных TXT более 500 МБ, поэтому я использовал команды Cygwin/SED для начальной очистки данных, а затем Python для порции файла. Поэтому в идеале процесс должен был бы добавить некоторый код в питон (см. Ниже), чтобы не включать все строки с Rx<=0.

Latitude    Longitude   Rx  Best_Unit
-16.37617    144.68805  -012.9  7
-16.37617    144.68834  -015.1  7
-16.37617    144.68861  -017.2  7
-16.37617    144.68890  -018.1  7
-16.37617    144.68919  -025.0  7
-16.37617    144.68945  -019.5  7
-16.37617    144.68974  -020.0  7
-16.37617    144.69003  -020.4  7
-16.37617    144.69623   015.3  7
-16.37617    144.69652   015.6  7
-16.37617    144.69679   015.8  7
-16.37617    144.69708   016.0  7
-16.37617    144.70076   005.0  7
-16.37617    144.70103   002.2  7
-16.37617    144.70131  -000.2  7
-16.37617    144.70160  -001.5  7
-16.37617    144.70187  -001.0  7
-16.37617    144.70216   000.7  7
-16.37617    144.70245   002.2  7
-16.37617    144.70273   008.4  7
-16.37617    144.70300   017.1  7
-16.37617    144.70329   017.2  7

Я хочу, чтобы все строки (строки), где Rx>0, были записаны в новый текстовый файл. Я также хочу удалить столбец Best_Unit.

from itertools import islice

import arcpy, os
#fc = arcpy.GetParameter(0)
#chunk_size = arcpy.GetParameter(1) # number of records in each dataset

fc='cb_vhn007_5.txt'
Name = fc[:fc.rfind('.')]
fl = Name+'.txt'

headers_count = 1
chunk_size = 500000

with open(fl) as fin:
  headers = list(islice(fin, headers_count))

  part = 1
  while True:
    line_iter = islice(fin, chunk_size)
    try:
      first_line = line_iter.next()
    except StopIteration:
      break
    with open(Name+'_%d.txt' % part, 'w') as fout:
      for line in headers:
        fout.write(line)
      fout.write(first_line)
      for line in line_iter:
         ## add something here to check if value after third tab
         ## is >0 and if so then write the row or skip.
        fout.write(line) 

    print "Created part %d" % part
    part += 1

Новый код - первая строка включает в себя - значения Rx.

from itertools import islice

import arcpy, os
#fc = arcpy.GetParameter(0)
#chunk_size = arcpy.GetParameter(1) # number of records in each dataset

fc='cb_vhn007_5.txt'
Name = fc[:fc.rfind('.')]
fl = Name+'.txt'

headers_count = 1
chunk_size = 500000

with open(fl) as fin:
  headers = list(islice(fin, headers_count))

  part = 1
  while True:
    line_iter = islice(fin, chunk_size)
    try:
      first_line = line_iter.next()
    except StopIteration:
      break
    with open(Name+'_%d.txt' % part, 'w') as fout:
      for line in headers:
        fout.write(line)
      fout.write(first_line)
      for line in line_iter:
        if line.split()[2][0:1] != '-':
          #print line.split()[2]
          fout.write(line)

    print "Created part %d" % part
    part += 1

5 ответов

Решение

Ты можешь использовать line.split() разделить вашу строку в список, содержащий значение каждого из 4 столбцов.

Например:

line='-16.37617\t144.70329\t017.2\t7'
line.split()
# ['-16.37617', '144.70329', '017.2', '7']

Тогда вы можете заставить line[2] (помните, что python - индексирование на основе 0) к числу и проверьте, является ли он> 0:

if float(line.split()[2]) > 0:
    fout.write(line)

Или вы можете просто проверить, есть ли в нем знак минус:

if line.split()[2].find('-') != -1:
    fout.write(line)

Если ваши столбцы могут быть не в том же порядке для каждого текстового файла, вы можете выполнить split() по заголовкам определите, какой Rxи используйте это вместо 2:

i = headers.split().index('Rx')
# now use line[i]

Наверное просто проверяю line_iter[24] != '-' должно быть достаточно.

Т.е. заменить:

fout.write(line)

с

if line_iter[24] != '-':
  fout.write(line)

Я знаю, что это не Python, но это, вероятно, правильный инструмент для работы:

cat cb_vhn007_5.txt | awk '($3 > 0) {print $0}' > parsedfile

Строки, которые вы ищете, примерно такие:

if line.split()[2][0:1] != "-"
  fout.write(line)

Это разделяет ввод, просматривает третью запись, просматривает первый символ и пропускает печать строки, если это -,

Вот скрипт Python, который будет читать файл, содержащий данные, отформатированные в виде четырех разделенных пробелами полей в строке, проверять третье поле и выводить любые строки, третье поле которых является положительным числом с плавающей запятой.

Протестировано работает на Python 2.7.2.

import re

in_fh = open ("gis.txt","r")
out_fh = open ("outfile.txt","w")

for row in in_fh:
    row = re.sub(' +',',',row) # convert to comma-separated format
    try:
        latitude, longitude, rx, best_unit = row.split(',')
    except ValueError: # row didn't have four fields
        print ("complain - not four fields")
        continue

    try:
        float_rx = float(rx)
    except ValueError: # rx could not be cast to float
        print ("complain - third field not float")
        continue

    if float_rx > 0:
        out_fh.write(latitude + "," + longitude + "," + rx + "\n")
    else:
        pass # discard the row

in_fh.close()
out_fh.close()

Одновременно обрабатывается только одна строка, поэтому использование памяти должно быть постоянным независимо от размера входных и выходных файлов.

Альтернативно, вы рассматривали возможность использования базы данных? sqlite3 встроен и, вероятно, будет нормально обрабатывать 1 ГБ данных. Тогда вы могли бы получить этот результат, выполнив SELECT * FROM data WHERE rx > 0,

Другие вопросы по тегам