Как подсчитать каждое вхождение каждого числа в большой файл - PullRequest
1 голос
/ 15 марта 2019

Я довольно новичок в Python, и мне было интересно, если кто-нибудь может помочь мне решить эту проблему.

У меня большой текстовый файл с более чем 6 миллионами строк, но в каждой строке есть только одна пара «x, y» с относительно маленькими числами x и y.

Что мне нужно сделать, так это подсчитать в Python каждое вхождение каждой пары «x, y» в моем файле и записать их в документ Excel, где каждая строка представляет «y» и каждый столбец, "х".

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

Так что мне было интересно, есть ли способ быстрее или нет.

Имейте в виду, что я действительно не так хорош в программировании, как я только начал.

Большое спасибо за потенциальные ответы.

Вот мой код:

import xlsxwriter

book = xlsxwriter.Workbook("MyCount.xlsx")

sheet1 = book.add_worksheet('Sheet 1')

sheet1.write(0,0,'y\x')

for i in range (0,1441):
    sheet1.write(0,i+1,i)

for i in range (1,118):
    sheet1.write(i,0,i)

file1=open("Data.txt","r")

count=0

for x in range (0, 1441):
    for y in range (1, 118):
        count=0
        number=f'{x}'+','+f'{y}'+'\n'
        for line in file1.readlines():
            if line == number:
                count+=1
        sheet1.write(y, x+1, count)
        file1.seek(0)

file1.close()
book.close()

Ответы [ 3 ]

1 голос
/ 15 марта 2019

Вот (непроверенная ...) улучшенная версия решения Александру (примечание: я уже писал этот ответ, когда Алексендру разместил его, но, поскольку он отправил первым, пожалуйста, дайте ему кредит, если он поможет решить вашу проблему).

Общая идея состоит в том, чтобы сделать только один проход файла вместо 170038 (=> 1441 * 118) последовательных последовательных сканирований и уменьшить количество вызовов sheet.write() до числа найденных строк вместо перезаписи одного и того же клетки снова и снова и снова.

Также использование функций будет способствовать более быстрому выполнению, так как доступ к локальным переменным быстрее, чем с глобальными.

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

NB: диктор 6M {(int,int):int} легко помещается в память большинства современных компьютеров (только что попробовал на моем, который уже довольно занят), так что это не проблема (и вы все равно уже читали весь файл в памяти, что, вероятно, гораздо тяжелее по сравнению с памятью ...)

from collections import defaultdict

def parse_file():
    counts = defaultdict(int)
    with open("Data.txt") as f:
        for lineno, line in enumerate(f):
            line = line.strip()
            if not line:
                continue
            try:
                xy = tuple(int(i) for i in line.split(","))
            except (TypeError, ValueError) as e:
                print("oops, line {} is broken ? (found '{}')".format(lineno, line))
                continue
            counts[xy] += 1
    return counts


def write_counts(counts):
    book = xlsxwriter.Workbook("MyCount.xlsx")
    sheet1 = book.add_worksheet('Sheet 1')
    sheet1.write(0,0,'y\x')
    for i in range (0,1441):
       sheet1.write(0,i+1,i)
    for i in range (1,118):
        sheet1.write(i,0,i)

    for (x, y), count in counts.items():
        sheet1.write(y, x+1, count)


def main():
    counts = parse_file()
    write_counts(counts)

if __name__ == "__main__":
    main()
1 голос
/ 15 марта 2019

Итак, взгляните на это:

counts = {}

for line in open("data.txt", "r"):
    line = line.split(',')

    number_1 = None
    number_2 = None

    for line_element in line:

        try:
            number = int(line_element)
            if number_1 is None:
                number_1 = number
            else:
                number_2 = number
        except Exception:
            pass

    if number_1 and number_2:
        numbers_couple = '{},{}'.format(number_1, number_2)

        if numbers_couple in counts:
            counts[numbers_couple] += 1
        else:
            counts[numbers_couple] = 1

print(counts)

Содержимое моего data.txt:

a,b,c,20,30,dad,glaas
fdls,cafd,erer,fdesf,2,4534
fdls,cafd,erer,fdesf,2,11

И результат:

{
   '20,30': 1, 
   '2,4534': 1, 
   '2,11': 1
}

Вы могли использовать этот результат, чтобы записать его в новый файл, как вы упомянули, разделив ключи словаря, чтобы получить x и y.

Так вот так я посчитал пары чисел в файле, как вы описали. Это то, что вы ищите? Пожалуйста, дайте мне знать.

0 голосов
/ 15 марта 2019

Я думаю, это было бы более элегантным решением для вас. Считайте файл в файл данных pandas, сгруппируйте и подсчитайте пары.

import pandas as pd
d = [(1,2,3),(1,2,4),(1,2,1),(1,1,5),(1,4,5),(1,1,8)]

cntdt = pd.DataFrame(d,columns=['x','y','cnt'])
cntdt.head()

s = cntdt.groupby(['y','x']).size()

#to get the dataframe
s.to_frame('count').reset_index()

#to get the dictionary
s.to_dict()

вывод словаря: {(1, 1): 2, (2, 1): 3, (4, 1): 1} Выходные данные кадра:

<table border="1" class="dataframe"> <thead>   <tr style="text-align: right;">     <th></th>     <th>y</th>     <th>x</th>     <th>count</th>   </tr> </thead> <tbody>   <tr>     <th>0</th>     <td>1</td>     <td>1</td>     <td>2</td>   </tr>   <tr>     <th>1</th>     <td>2</td>     <td>1</td>     <td>3</td>   </tr>   <tr>     <th>2</th>     <td>4</td>     <td>1</td>     <td>1</td>   </tr> </tbody></table>
...