Как подсчитать каждое вхождение каждого числа в большой файл

#python #file #numbers #counting

#python #файл #числа #подсчет

Вопрос:

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

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

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

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

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

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

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

Вот мой код на данный момент:

 import xlsxwriter

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

sheet1 = book.add_worksheet('Sheet 1')

sheet1.write(0,0,'yx')

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()
  

Комментарии:

1. Образец данных вашего файла?

2. Что вы имеете в виду? Мой файл имеет вид: 120,52 50,30… где в каждой строке записано два числа, как показано выше, и каждая строка не уникальна.

3. Вы показали 4 числа и говорите «два числа, записанные так, как показано выше»

4. Имеет ли каждая строка разные пары чисел? Эти числа всегда в парах? Эти числа представлены в виде целых чисел или строк?

5. показать пример, например, row1 и row2

Ответ №1:

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

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

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

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

ПРИМЕЧАНИЕ: 6M {(int,int):int} dict легко помещается в память большинства современных компьютеров (только что попробовал на моем, который уже довольно занят), так что это не проблема (и вы все равно уже читали весь файл в памяти, что, вероятно, намного тяжелее по сравнению с памятью …)

 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,'yx')
    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. Решение Александри сработало нормально, мне просто нужно записать другое количество в документе Excel. Для информации, ваше решение выдало мне эту ошибку: write_counts for (x, y), count в counts.items(): AttributeError: объект ‘NoneType’ не имеет атрибута ‘items’ ; Тем не менее, спасибо за ваше время

2. @Peter виноват, я забыл вернуть counts из parse indeed (исправлено).

3. @Peter итак, это значительно быстрее?-)

4. бесконечно больше: 30 секунд

5. Это действительно улучшение xD

Ответ №2:

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

 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
}
  

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

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

Комментарии:

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

2. Ваше решение сработало нормально, мне просто нужно записать другое количество в документ Excel, который я попытаюсь найти сам. Я так благодарен. Большое спасибо за ваше время.

3. @Peter возможно, вы захотите хотя бы повысить голос за ответ Александру

4. Я подсчитал, но у меня недостаточно репутации

Ответ №3:

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

 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>