Python - Лучший способ сравнить две строки, записи статистики, сравнивая серийные позиции конкретного элемента? - PullRequest
2 голосов
/ 26 сентября 2010

Я имею дело с двумя файлами, у каждого из которых есть строки, похожие на следующие:

Это || пример || линия .

В одном из файлов появится указанная выше строка, тогда как соответствующая строка в другом файле будет идентичной, НО может иметь '||' предметы в другой позиции:

Это || это || пример || линия.

Мне просто нужно собрать статистику о том, как часто "||" попал в «правильное» место во втором файле (мы предполагаем, что первый файл всегда «правильный»), как часто «||» попал в место, где в первом файле не было "||", а как общее число "||" маркеры отличались для этой конкретной линии.

Я знаю, что мог бы сделать это один, но удивлялся, знали ли вы, блестящие люди, какой-нибудь невероятно легкий способ сделать это? Основные вещи (такие как чтение файлов) - это все, с чем я знаком - на самом деле я просто ищу совет о том, как проводить реальные сравнения строк и собирать статистику!

Best, Джорджина

Ответы [ 2 ]

1 голос
/ 26 сентября 2010

Это то, что вы ищете?

Этот код предполагает, что каждая строка отформатирована так же, как в ваших примерах

fileOne = open('theCorrectFile', 'r')
fileTwo = open('theSecondFile', 'r')

for corrrectLine in fileOne:
    otherLine = fileTwo.readline()
    for i in len(correctLine.split("||")):
        count = 0
        wrongPlacement = 0
        if (len(otherLine.split("||")) >= i+1) and (correctLine.split("||")[i] == otherLine.split("||")[i]):
            count += 1
        else:
            wrongPLacement += 1
print 'there are %d out of %d "||" in the correct places and %d in the wrong places' %(count, len(correctLine.split("||"), wrongPlacement)
0 голосов
/ 27 сентября 2010

Я не уверен, насколько это легко, поскольку в нем используются некоторые более продвинутые концепции, такие как генераторы, но, по крайней мере, они надежны и хорошо документированы. Фактический код находится внизу и довольно лаконичен.

Основная идея заключается в том, что функция iter_delim_sets возвращает итератор для (или последовательность) кортежей, содержащих номер строки, набор индексов в «ожидаемой» строке, где был найден разделитель, и аналогичный набор для «фактическая» строка. Существует один такой кортеж, сгенерированный для каждой пары (ожидаемых, результирующих) строк. Эти кортежи кратко формализованы в тип collections.namedtuple, называемый DelimLocations.

Тогда функция analyze просто возвращает информацию более высокого уровня, основанную на таком наборе данных, сохраненную в DelimAnalysis namedtuple. Это делается с использованием алгебры базовых множеств.

"""Compare two sequences of strings.

Test data:
>>> from pprint import pprint
>>> delimiter = '||'
>>> expected = (
...     delimiter.join(("one", "fish", "two", "fish")),
...     delimiter.join(("red", "fish", "blue", "fish")),
...     delimiter.join(("I do not like them", "Sam I am")),
...     delimiter.join(("I do not like green eggs and ham.",)))
>>> actual = (
...     delimiter.join(("red", "fish", "blue", "fish")),
...     delimiter.join(("one", "fish", "two", "fish")),
...     delimiter.join(("I do not like spam", "Sam I am")),
...     delimiter.join(("I do not like", "green eggs and ham.")))

The results:
>>> pprint([analyze(v) for v in iter_delim_sets(delimiter, expected, actual)])
[DelimAnalysis(index=0, correct=2, incorrect=1, count_diff=0),
 DelimAnalysis(index=1, correct=2, incorrect=1, count_diff=0),
 DelimAnalysis(index=2, correct=1, incorrect=0, count_diff=0),
 DelimAnalysis(index=3, correct=0, incorrect=1, count_diff=1)]

What they mean:
>>> pprint(delim_analysis_doc)
(('index',
  ('The number of the lines from expected and actual',
   'used to perform this analysis.')),
 ('correct',
  ('The number of delimiter placements in ``actual``',
   'which were correctly placed.')),
 ('incorrect', ('The number of incorrect delimiters in ``actual``.',)),
 ('count_diff',
  ('The difference between the number of delimiters',
   'in ``expected`` and ``actual`` for this line.')))

And a trace of the processing stages:
>>> def dump_it(it):
...     '''Wraps an iterator in code that dumps its values to stdout.'''
...     for v in it:
...         print v
...         yield v

>>> for v in iter_delim_sets(delimiter,
...                          dump_it(expected), dump_it(actual)):
...     print v
...     print analyze(v)
...     print '======'
one||fish||two||fish
red||fish||blue||fish
DelimLocations(index=0, expected=set([9, 3, 14]), actual=set([9, 3, 15]))
DelimAnalysis(index=0, correct=2, incorrect=1, count_diff=0)
======
red||fish||blue||fish
one||fish||two||fish
DelimLocations(index=1, expected=set([9, 3, 15]), actual=set([9, 3, 14]))
DelimAnalysis(index=1, correct=2, incorrect=1, count_diff=0)
======
I do not like them||Sam I am
I do not like spam||Sam I am
DelimLocations(index=2, expected=set([18]), actual=set([18]))
DelimAnalysis(index=2, correct=1, incorrect=0, count_diff=0)
======
I do not like green eggs and ham.
I do not like||green eggs and ham.
DelimLocations(index=3, expected=set([]), actual=set([13]))
DelimAnalysis(index=3, correct=0, incorrect=1, count_diff=1)
======
"""
from collections import namedtuple


# Data types

## Here ``expected`` and ``actual`` are sets
DelimLocations = namedtuple('DelimLocations', 'index expected actual')

DelimAnalysis = namedtuple('DelimAnalysis',
                           'index correct incorrect count_diff')
## Explanation of the elements of DelimAnalysis.
## There's no real convenient way to add a docstring to a variable.
delim_analysis_doc = (
    ('index', ("The number of the lines from expected and actual",
               "used to perform this analysis.")),
    ('correct', ("The number of delimiter placements in ``actual``",
                 "which were correctly placed.")),
    ('incorrect', ("The number of incorrect delimiters in ``actual``.",)),
    ('count_diff', ("The difference between the number of delimiters",
                    "in ``expected`` and ``actual`` for this line.")))


# Actual functionality

def iter_delim_sets(delimiter, expected, actual):
    """Yields a DelimLocations tuple for each pair of strings.

    ``expected`` and ``actual`` are sequences of strings.
    """
    from re import escape, compile as compile_
    from itertools import count, izip
    index = count()

    re = compile_(escape(delimiter))
    def delimiter_locations(string):
        """Set of the locations of matches of ``re`` in ``string``."""
        return set(match.start() for match in re.finditer(string))

    string_pairs = izip(expected, actual)

    return (DelimLocations(index=index.next(),
                           expected=delimiter_locations(e),
                           actual=delimiter_locations(a))
            for e, a in string_pairs)

def analyze(locations):
    """Returns an analysis of a DelimLocations tuple.

    ``locations.expected`` and ``locations.actual`` are sets.
    """
    return DelimAnalysis(
        index=locations.index,
        correct=len(locations.expected & locations.actual),
        incorrect=len(locations.actual - locations.expected),
        count_diff=(len(locations.actual) - len(locations.expected)))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...