Как определить отсутствующие индексы - PullRequest
3 голосов
/ 15 мая 2019

У меня есть текстовый файл с миллионами индексных точек, которые все интерпретируются как строки и разделены табуляцией.Однако некоторые индексные точки могут отсутствовать.Вот пример моего текстового файла:

1       0       4         0d 07:00:37.0400009155273   
2       0       4         0d 07:00:37.0400009155273   
3       0       4         0d 07:00:37.0400009155273   
5       0       4         0d 07:00:37.0400009155273   
7       0       4         0d 07:00:37.0400009155273   
9       0       4         0d 07:00:37.0400009155273

Обратите внимание, что строки 4, 6 и 8 отсутствуют.Моя цель - создать функцию, которая может анализировать текстовый файл, определять возможные отсутствующие индексные точки и возвращать список, в котором есть все отсутствующие индексные точки (если есть), или ничего не возвращать.

Я использую Python3.7 в Spyder IDE Windows10 OS.Я относительно новичок в Python и Stackoverflow.

Это то, что у меня так далеко.Это работает для ID 1 отсутствующего индекса, но завершается неудачей, если есть несколько отсутствующих индексных точек.

Ошибка начинается после первой строки else.Я не уверен, как отследить наблюдаемый индекс в документе (1, 2, 3, 5 ...) с индексом цикла for (0, 1, 2, 3 ...), поскольку отсутствующие индексные точки со временем составляют,

Обратите внимание, что первые 4 строки текстового документа содержат информацию заголовка, которую я игнорирую при разборе, поэтому data = f.readlines () [4:]

  def check_sorted_file(fileName):
        missing_idx = []
        count = 1
            with open(fileName, 'r') as f:
                data = f.readlines()[4:]
                for x, line in enumerate(data):
                    idx = int(line.split()[0])
                    if idx == (count + x): 
                        pass
                    else: 
                        missing_idx.append(count + x)
                        count += 1
                if missing_idx != []:
                    print('\nThe following idicie(s) are missing: ')
                    print(*missing_idx, sep=", ")
                else:   
                    print('\nAll indices are accounted for. ')
                return missing_idx

...

Спасибо за любую помощь!

Ответы [ 4 ]

1 голос
/ 15 мая 2019

Другой ответ дает вам гораздо лучшие общие решения, однако я хочу просто помочь направить ваш заданный в правильном направлении, чтобы вы увидели, как вы можете изменить свои для работы:

def check_sorted_file(fileName):
    missing_idx = []
    last_index = 0
    with open(fileName, 'r') as f:
        data = f.readlines()[4:]

    for line in data:
        idx = int(line.split()[0])
        if idx == last_index+1:
            pass
        else:
            missing_idx.extend(list(range(last_index+1, idx)))
        last_index = idx

    if missing_idx:
        print('\nThe following idicie(s) are missing: ')
        print(*missing_idx, sep=", ")
    else:
        print('\nAll indices are accounted for. ')
    return missing_idx

Таким образом, вместо того, чтобы использовать перечисление, мы будем использовать входящий индекс в качестве руководства, где мы находимся.

Чтобы решить несколько пропущенных, мы используем range, чтобы получить все числа между последним и текущим индексами, и расширяем наш список этим новым набором чисел.

1 голос
/ 15 мая 2019

Поскольку у вас большое количество строк, вы можете сделать это ленивым способом, не создавая больших списков или не используя in, чтобы проверить, находится ли каждое значение в списке из миллиона строк.Вы можете смешать несколько itertools, чтобы сделать это как итератор и сохранить список для конца (если он вам тогда даже понадобится).

В основном вы делаете tee a map на два итератора, чтобы получить индексы, отбрасываете значение одного из них с помощью next(), а затем архивируете их, проверяя разницу по ходу:

from itertools import chain, tee
lines = ["1       0       4         0d 07:00:37.0400009155273",
"2       0       4         0d 07:00:37.0400009155273",
"3       0       4         0d 07:00:37.0400009155273",
"5       0       4         0d 07:00:37.0400009155273",
"7       0       4         0d 07:00:37.0400009155273",
"9       0       4         0d 07:00:37.0400009155273"
]

#two iterators going over indexes 
i1, i2 = tee(map(lambda x: int(x.split()[0]), lines), 2)

# move one forward
next(i2) 

# chain.from_iterable will be an iterator producing missing indexes: 
list(chain.from_iterable(range(i+1, j) for i, j in zip(i1, i2) if j-i!=1))

Результат:

[4, 6, 8]
1 голос
/ 15 мая 2019

Вы можете сделать это только с помощью Python:

with open(filename) as f:
    indices = [int(row.split('\t')[0]) for row in f.read().split('\n')[4:]]

missing_indices = [index 
                   for index in range(1, len(indices) + 1)
                   if index not in indices]

Это преобразует ваши данные во вложенный list, где каждый внешний list содержит строку, а каждый внутренний list содержит элемент. Поскольку нам важны только индексы, мы получаем первый элемент и игнорируем остальные.

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

Предполагая, что индексы уникальны (что кажется разумным), мы также можем использовать предложение DYZ для использования sets:

missing_indices = set(range(1, len(indices) + 1) - set(indices)

pandas тоже отлично работает:

import pandas as pd

df = pd.read_csv(filename, sep='\t').iloc[4:]

range_index = pd.RangeIndex(1, len(df) + 1)
print(range_index[~range_index.isin(df.iloc[:, 0])]

Это создает pandas DataFrame из ваших данных, обрезая первые четыре строки. Следуя тому же принципу, что и другой ответ, он создает индекс со всеми ожидаемыми значениями и берет его подмножество, которого нет в первом столбце DataFrame.

0 голосов
/ 15 мая 2019

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

skip = 4 # Skip that many lines
with open(yourfile) as f:
    for _ in range(skip):
        next(f)
    actual = {int(line.split()[0]) for line in f}

Создайте набор ожидаемых индексов и определите разницу:

expected = set(range(min(actual), max(actual) + 1))
sorted(expected - actual)
#[4, 6, 8]

Решение работает, даже если индексы не начинаются с 1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...