Подача списка списков в функцию

1

У меня есть многомерный массив, который я пытаюсь передать в difflib.get_close_matches().

Мой массив выглядит так: array[(ORIGINAL, FILTERED)]. ORIGINAL - это строка, а FILTERED - строка ORIGINAL с отфильтрованными общими словами.

В настоящее время я создаю новый массив, в котором в difflib.get_close_matches() подаются только слова FILTERED. Затем я попытаюсь сопоставить результат с difflib с array[(ORIGINAL, FILTERED)]. Моя проблема заключается в том, что часто у меня есть два или более слова FILTERED, которые эквивалентны, и поэтому они не могут быть сопоставлены с использованием этого метода.

Есть ли способ, в котором я могу передать весь array[(ORIGINAL,FILTERED)] в difflib, но посмотрите ли он только на часть FILTERED (при возвращении [(ORIGINAL,FILTERED)]?)

Спасибо заранее!

import  time
import  csv
import  difflib
import  sys
import  os.path
import  datetime

### Filters out common  words   in  an  attempt to  get better      results ###
def ignoredWords (word):
    filtered = word.lower()
    #Common Full Words
## Majority of filters were edited out
    #Common Abbreviations
    if "univ" in filtered:
        filtered = filtered.replace("univ","")
    #Special Characters
    if "  " in filtered: #Two White Spaces
        filtered = filtered.replace("  "," ")
    if "-" in filtered:
        filtered = filtered.replace("-"," ")
    if "\'" in filtered:
        filtered = filtered.replace("\'"," ")
    if " & " in filtered:
        filtered = filtered.replace(" &","")
    if "(\"" in filtered:
        filtered = filtered.replace("(\"","")
    if "\")" in filtered:
        filtered = filtered.replace("\")","")
    if "\t" in filtered:
        filtered = filtered.replace("\t"," ")
    return  filtered

### Takes in a list, then outputs a 2D list. array[Original, Filtered] ###
### For XXX: array[Original, Filtered, Account Number, Code] ###
def create2DArray (list):
    array = []
    for item in list:
        clean = ignoredWords(item[2])
        entry = (item[2].lower(), clean, item[0],item[1])
        array.append(entry)
    return array

def main(argv):
    if(len(argv) < 3):
        print "Not enough parameters. Please enter two file names"
        sys.exit(2)
    elif (not os.path.isfile(argv[1])):
        print "%s is not found" %(argv[1])
        sys.exit(2)
    elif (not os.path.isfile(argv[2])):
        print "%s is not found" %(argv[2])
        sys.exit(2)
    #Recode File ----- Not yet implemented
#       if(len(argv) == 4):
#       if(not os.path.isfile(argv[3])):
#           print "%s is not found" %(argv[3])
#           sys.exit(2)
#           
#       recode = open(argv[1], 'r')
#       try:
#           setRecode = c.readlines()
#       finally:
#           recode.close()
#           setRecode.sort()
#           print setRecode[0]
    #Measure execution time
    t0 = time.time()

    cReader = csv.reader(open(argv[1], 'rb'), delimiter='|')
    try:
        setC = []
        for row in cReader:
            setC.append(row)
    finally:
        setC.sort()

    aReader = csv.reader(open(argv[2], 'rb'), delimiter='|')
    try:
        setA = []
        for row in aReader:
            setA.append(row)
    finally:
        setA.sort()

    #Put Set A and Set C into their own 2 dimmensional arrays.array[Original Word]    [Cleaned Up Word]
    arrayC = create2DArray(setC)
    arrayA = create2DArray(setA)

    #Create clean list versions for use with difflib
    cleanListC = []
    for item in arrayC:
        cleanListC.append(item[1])

    cleanListA = []
    for item in arrayA:
        cleanListA.append(item[1])

    ############OUTPUT FILENAME############
    fMatch75 = open("Match75.csv", 'w')
    Match75 = csv.writer(fMatch75, dialect='excel')
    try:
        header = "Fuzzy Matching Report. Generated: "
        header += str(datetime.date.today())
        Match75.writerow([header])
        Match75.writerow(['C','A','C Cleaned','A Cleaned','C Account', 'C Group','A Account', 'A Group', 'Filtered Ratio %','Unfiltered Ratio %','Average Ratio %'])
        for item in cleanListC:
            match = difflib.get_close_matches(item,cleanListA,1,0.75)

            if len(match) > 0:
                filteredratio = difflib.SequenceMatcher(None,item,match[0]).ratio()
                strfilteredratio = '%.2f' % (filteredratio*100)
                found = 0
                for group in arrayA:
                    if match[0] == group[1]:
                        origA = group[0]
                        acode = group[3]
                        aaccount = group[2]
                        found = found + 1
                for group in arrayC:
                    if item == group[1]:
                        origC = group[0]
                        ccode = group[3]
                        caccount = group[2]
                        found = found + 2
                if found == 3:
                    unfilteredratio = difflib.SequenceMatcher(None,origC,origA).ratio()
                    strunfilteredratio = '%.2f' % (unfilteredratio*100)
                    averageratio = (filteredratio+unfilteredratio)/2
                    straverageratio = '%.2f' % (averageratio*100)

                    row = [origC.rstrip(),origA.rstrip(),item.rstrip(),match[0].rstrip(),caccount,ccode,aaccount,acode,strfilteredratio,strunfilteredratio,straverageratio]
                    Match75.writerow(row)
                #These Else Ifs are for debugging. If NULL is found anywhere in the CSV, then an error has occurred
                elif found == 2:
                    row = [origC.rstrip(),"NULL",item.rstrip(),match[0].rstrip(),caccount,ccode,"NULL","NULL",strfilteredratio,"NULL","NULL"]
                    Match75.writerow(row)
                elif found == 1:
                    row = ["NULL",origA.rstrip(),item.rstrip(),match[0].rstrip(),"NULL","NULL",aaccount,acode,strfilteredratio,"NULL","NULL"]
                    Match75.writerow(row)
            else:
                    row = ["NULL","NULL",item.rstrip(),match[0].rstrip(),"NULL","NULL","NULL","NULL",strfilteredratio,"NULL","NULL"]
                    Match75.writerow(row)

    finally:
        Match75.writerow(["A Proprietary and Confidential. Do Not Distribute"])
        fMatch75.close()

    print (time.time()-t0,"seconds")

if __name__ == "__main__":
    main(argv=sys.argv)

То, что я пытаюсь достичь:

  • Чтение входных файлов
  • Отфильтруйте общие слова от имен, чтобы нечеткое соответствие ('difflib.get_close_matches()') вернуло более точные результаты
  • Сравните имена файлов FileA с именами в FileB, чтобы найти, какой из них, скорее всего, соответствует.
  • Распечатайте исходные (нефильтрованные) имена и процент соответствия.

Почему это сложно

Соглашения об именах, используемые в двух входных файлах, значительно различаются. Некоторые имена частично сокращены (EX: File A: Acme Company, файл B: Acme Co). Поскольку соглашения об именах несовместимы, я не могу сделать "FileA.intersect(FileB)", что было бы идеальным способом.

Где должна произойти модификация

for item in cleanListC:
    match = difflib.get_close_matches(item,cleanListA,1,0.75)

CleanListA создается:

cleanListA = []
    for item in arrayA:
        cleanListA.append(item[1])

Таким образом, теряется спаривание (ORIGINAL,FILTERED).

Конечная цель

Я хотел бы передать arrayA в difflib.get_close_matches() вместо cleanListA, чтобы сохранить спаривание (ORIGINAL,FILTERED). difflib.get_close_matches() будет рассматривать только "ФИЛЬТРИРОВАННУЮ" часть спаривания при определении совпадений, но возвращает полное спаривание.

  • 0
    @MikeKusold Что вы имеете в виду под именем «массив»? В Python я понимаю, что: ( docs.python.org/library/array.html#module-array )
  • 0
    Я использовал массив [ORIGINAL, FILTERED] в качестве средства для четкого описания моей переменной. Вы можете также легко заменить слова [(Оригинал, Отфильтрованные)].
Показать ещё 7 комментариев
Теги:

1 ответ

0
Лучший ответ

Поскольку вы уже используете SequenceMatcher напрямую, чтобы получить коэффициент соответствия, ваши самые простые изменения, вероятно, состоят в том, чтобы выполнить операцию get_close_matches самостоятельно.

Сравните источник для get_close_matches(), http://svn.python.org/view/python/tags/r271/Lib/difflib.py?revision=86833&view=markup рядом с линией 737]. Он возвращает список из n последовательностей с наивысшими коэффициентами. Поскольку вы хотите только лучшее совпадение, вы можете отслеживать соотношение (ОРИГИНАЛЬНОЕ, ФИЛЬТРИРОВАННОЕ), где отношение является самым высоким до сих пор, вместо heapq исходный метод использует для отслеживания наивысшего значения.

Например, вместо вашего основного цикла, например:   

seqm = difflib.SequenceMatcher()

for i in arrayC:
  origC, cleanC, caccount, ccode = i
  seqm.set_seq2(cleanC)

  bestRatio = 0

  for j in arrayA:
    origA, cleanA = j[:2]
    seqm.set_seq1(cleanA)

    if (seqm.real_quick_ratio() >= bestRatio and
        seqm.quick_ratio() >= bestRatio):
      r = seqm.ratio()
      if r >= bestRatio:
        bestRatio = r
        bestA = j

  if bestRatio >= 0.75: # the cutoff from the original get_close_matches() call
    origA, cleanA, aaccount, acode = bestA

    filteredratio = bestRatio
    strfilteredratio = '%.2f' % (filteredratio*100)

    seqm.set_seqs( origC, origA )
    unfilteredratio = seqm.ratio()
    strunfilteredratio = '%.2f' % (unfilteredratio*100)

    averageratio = (filteredratio+unfilteredratio)/2
    straverageratio = '%.2f' % (averageratio*100)

    row = [origC.rstrip(),origA.rstrip(),cleanC.rstrip(),cleanA.rstrip(),caccount,ccode,aaccount,acode,strfilteredratio,strunfilteredratio,straverageratio]
  else:
    row = ["NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","0.00","NULL","NULL"]

  Match75.writerow(row)
  • 0
    Я закончил идти этим путем. Я надеялся, что в списке есть способ подачи, например list [1] [i] или что-то еще, но это тоже сработало.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню