Как я могу только извлечь строки из файла, если столбец 1 происходит, по крайней мере, n-времена?

существует ли способ отобразить строки, содержащие определенные строки (как почтительный::: N в примере ниже), которые не происходят в течение времен N в определенном файле?

Я знаю, что могу считать возникновение некоторой строки с grep, запишите это в новый файл и затем считайте строки с wc -l. Однако у меня есть огромный файл, где я должен отфильтровать строки, где строка в столбце 1 не появляется 5 раз в столбце 1 файла.

Предложения очень ценятся.

редактирование строки в file_1.txt в алфавитном порядке отсортировано по первому столбцу. Файл содержит приблизительно 1 000 000 строк, я мог также разломать его на несколько маленьких файлов, конечно. Порядок вывода не имеет значения.

file_1.txt

realism:::N     1.33    depth:::N               3.11    341
realism:::N     1.33    problem:::N             2.68    335
realism:::N     1.33    now:::ADV               1.48    335
realism:::N     1.33    life:::N                2.69    334
renowned:::ADJ  1.41    be:::V                  1.85    15760
renowned:::ADJ  1.41    internationally:::ADV   2.23    9134
renowned:::ADJ  1.41    world:::N               4.36    6736
renowned:::ADJ  1.41    most:::ADV              2.38    5482
reverent:::ADJ  1.5     use:::V                 2.78    25
reverent:::ADJ  1.5     sacred:::ADJ            1.77    25
reverent:::ADJ  1.5     music:::N               4.31    25
reverent:::ADJ  1.5     devout:::ADJ            2.46    25
reverent:::ADJ  1.5     devotion:::N            2.36    25

output_file.txt

reverent:::ADJ  1.5 use:::V         2.78    25
reverent:::ADJ  1.5 sacred:::ADJ    1.77    25
reverent:::ADJ  1.5 music:::N       4.31    25
reverent:::ADJ  1.5 devout:::ADJ    2.46    25
reverent:::ADJ  1.5 devotion:::N    2.36    25
2
задан 18 February 2017 в 21:49

2 ответа

awk со справкой от замены процесса (<()), sort, и uniq:

awk 'NR==FNR{a[$0]; next} {for (i in a) if ($1==i) {print}}' \
      <(awk '{print $1}' file.txt | sort| uniq -c | awk '$1 >= 5 {print $2}') file.txt
  • awk '{print $1}' file.txt | sort| uniq -c | awk '$1 >= 5 {print $2}' получает первые поля, где содержание происходит больше, чем или равный 5 разам. Замена команды, <(), заменяет STDOUT дескриптором файла, который передается как первый аргумент основному рабочему awk процесс, с исходным входным файлом как второй

  • NR==FNR{a[$0]; next} создает массив a с элементами из первого файла (NR==FNR) как ключи

  • {for (i in a) if ($1==i) {print}}' печатает строки от file.txt это имеет ключи от массива a как первое поле


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


Пример:

% cat file.txt                                                                                                     
realism:::N     1.33    depth:::N               3.11    341
realism:::N     1.33    problem:::N             2.68    335
realism:::N     1.33    now:::ADV               1.48    335
realism:::N     1.33    life:::N                2.69    334
renowned:::ADJ  1.41    be:::V                  1.85    15760
renowned:::ADJ  1.41    internationally:::ADV   2.23    9134
renowned:::ADJ  1.41    world:::N               4.36    6736
renowned:::ADJ  1.41    most:::ADV              2.38    5482
reverent:::ADJ  1.5     use:::V                 2.78    25
reverent:::ADJ  1.5     sacred:::ADJ            1.77    25
reverent:::ADJ  1.5     music:::N               4.31    25
reverent:::ADJ  1.5     devout:::ADJ            2.46    25
reverent:::ADJ  1.5     devotion:::N            2.36    25

% awk 'NR==FNR{a[$0]; next} {for (i in a) if ($1==i) {print}}' <(awk '{print $1}' file.txt | sort| uniq -c | awk '$1 >= 5 {print $2}') file.txt
reverent:::ADJ  1.5     use:::V                 2.78    25
reverent:::ADJ  1.5     sacred:::ADJ            1.77    25
reverent:::ADJ  1.5     music:::N               4.31    25
reverent:::ADJ  1.5     devout:::ADJ            2.46    25
reverent:::ADJ  1.5     devotion:::N            2.36    25
1
ответ дан 2 December 2019 в 03:42

Принятие строк отсортировано (сгруппированное)

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

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

Это должно быть довольно быстро на больших файлах, хотя я не запускал тест времени (еще) на огромных файлах

Сценарий

#!/usr/bin/env python3
import sys

#-- set the minimum number below
n = 5
# don't change anything below
f = sys.argv[1]; out = sys.argv[2]; mark1 = ""; lines = []

def write_out(lines):
    if len(lines) >= n:
        with open(out, "a+") as wrt:
            for line in lines:
                wrt.write(line)

with open(f) as read:
    for l in read:
        mark2 = l.split()[0]
        if mark2 == mark1:
            lines.append(l)
        else:
            write_out(lines)
            lines = [l]
        mark1 = mark2
# add the last set of lines
write_out(lines)

Использовать

  1. Скопируйте сценарий в пустой файл, сохраните его как get_lines.py
  2. В заголовке сценария, определенного минимальный номер строк, начиная со строки.
  3. Выполните его с входным и выходным файлом как аргументы:

    python3 /path/to/get_lines.py <input_file> <output_file>
    

Вывод (как ожидалось) в output_file, если мы устанавливаем предел к 5:

reverent:::ADJ  1.5     use:::V                 2.78    25
reverent:::ADJ  1.5     sacred:::ADJ            1.77    25
reverent:::ADJ  1.5     music:::N               4.31    25
reverent:::ADJ  1.5     devout:::ADJ            2.46    25
reverent:::ADJ  1.5     devotion:::N            2.36    25
1
ответ дан 2 December 2019 в 03:42

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

Похожие вопросы: