Реализовать скользящее окно в строках файлов в Python

Я пытаюсь реализовать подход скользящего / движущегося окна в строках файла csv с помощью Python. В каждой строке может быть столбец с двоичным значениемyes или no. В основном хочу редкихyesшумы. Это означает, что если у нас есть 3 yesстрок в окне 5 (максимум 5), оставьте их. Но если их 1 или 2, давайте изменим их наno. Как я могу это сделать?

Например, следующие yes оба должны стать no.

...
1,a1,b1,no,0.75
2,a2,b2,no,0.45
3,a3,b3,yes,0.98
4,a4,b4,yes,0.22
5,a5,b5,no,0.46
6,a6,b6,no,0.20
...

Но в дальнейшем мы оставляем как есть (может быть окно 5, где 3 из них yes):

...
1,a1,b1,no,0.75
2,a2,b2,no,0.45
3,a3,b3,yes,0.98
4,a4,b4,yes,0.22
5,a5,b5,no,0.46
6,a6,b6,yes,0.20
...

Я попытался написать что-то, имея окно 5, но застрял (не полный):

        window_size = 5 
        filename='C:\\Users\\username\\v3\\And-'+v3file.split("\\")[5]
        with open(filename) as fin:
            with open('C:\\Users\\username\\v4\\And2-'+v3file.split("\\")[5],'w') as finalout:
                line= fin.readline()
                index = 0
                sequence= []
                accs=[]
                while line:
                    print(line)
                    for i in range(window_size):
                        line = fin.readline()
                        sequence.append(line)
                    index = index + 1
                    fin.seek(index)

2 ответа

Решение

Ты можешь использовать collections.deque с maxlenАргумент установлен на желаемый размер окна, чтобы реализовать скользящее окно, которое отслеживает флажки да / нет последних 5 строк. Для большей эффективности ведите подсчет ответов вместо того, чтобы вычислять сумму ответов в скользящем окне на каждой итерации. Если у вас есть полноразмерное скользящее окно и количество ответов превышает 2, добавьте индексы строк этих ответов в набор, в котором yeses следует оставить как есть. И во втором проходе после сброса файлового указателя ввода измените да на нет, если индексы строки не находятся в наборе:

from collections import deque

window_size = 5
with open(filename) as fin, open(output_filename, 'w') as finalout:
    yeses = 0
    window = deque(maxlen=5)
    preserved = set()
    for index, line in enumerate(fin):
        window.append('yes' in line)
        if window[-1]:
            yeses += 1
        if len(window) == window_size:
            if yeses > 2:
                preserved.update(i for i, f in enumerate(window, index - window_size + 1) if f)
            if window[0]:
                yeses -= 1
    fin.seek(0)
    for index, line in enumerate(fin):
        if index not in preserved:
            line = line.replace('yes', 'no')
        finalout.write(line)

Демо: https://repl.it/@blhsing/StripedCleanCopyrightinfringement

Вот 5-строчное решение, основанное на построении последовательного понимания списков:

lines = [
'1,a1,b1,no,0.75',
'2,a2,b2,yes,0.45',
'3,a3,b3,yes,0.98',
'4,a4,b4,yes,0.22',
'5,a5,b5,no,0.46',
'6,a6,b6,no,0.98',
'7,a7,b7,yes,0.22',
'8,a8,b8,no,0.46',
'9,a9,b9,no,0.20']

n = len(lines)

# flag all lines containing 'yes' (add 2 empty lines at boundaries to avoid pbs)
flags = [line.count('yes') for line in ['', '']+lines+['', '']]
# count number of flags in sliding window [p-2,p+2]
counts = [sum(flags[p-2:p+3]) for p in range(2,n+2)]
# tag lines that need to be changed
tags = [flag > 0 and count < 3 for (flag,count) in zip(flags[2:],counts)]
# change tagged lines
for n in range(n):
  if tags[n]: lines[n] = lines[n].replace('yes','no')

print(lines)

Результат:

['1,a1,b1,no,0.75',
 '2,a2,b2,yes,0.45',
 '3,a3,b3,yes,0.98',
 '4,a4,b4,yes,0.22',
 '5,a5,b5,no,0.46',
 '6,a6,b6,no,0.98',
 '7,a7,b7,no,0.22',
 '8,a8,b8,no,0.46',
 '9,a9,b9,no,0.20']

РЕДАКТИРОВАТЬ: когда вы читаете свои данные из стандартного текстового файла, все, что вам нужно сделать, это:

with file(filename,'r') as f:
  lines = f.read().strip().split('\n')

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

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