2014-01-05 3 views
0

У меня есть файл json data_large размером 150.1MB. Содержимое внутри файла имеет тип [{"score": 68},{"score": 78}]. Мне нужно найти список уникальных баллов по каждому предмету.Python - найти уникальные значения из большого json-файла эффективно

Это то, что я делаю: -

import ijson # since json file is large, hence making use of ijson 

f = open ('data_large') 
content = ijson.items(f, 'item') # json loads quickly here as compared to when json.load(f) is used. 
print set(i['score'] for i in content) #this line is actually taking a long time to get processed. 

Могу ли я сделать print set(i['score'] for i in content) линию более эффективной. В настоящее время он принимает 201secs для выполнения. Может ли он быть более эффективным?

+0

Смотрите также: [Этот вопрос на CodeReview.SE] (http://codereview.stackexchange.com/questions/38574/how-to-find-the-unique-values-from-the-json-file). – poke

ответ

2

Это даст вам набор уникальных значений баллов (только) как ints. Вам понадобится 150 МБ свободной памяти. Он использует re.finditer() для анализа, который примерно в три раза быстрее, чем json-парсер (на моем компьютере).

import re 
import time 
t = time.time() 
obj = re.compile('{.*?: (\d*?)}') 
with open('datafile.txt', 'r') as f: 
    data = f.read() 
s = set(m.group(1) for m in obj.finditer(data)) 
s = set(map(int, s)) 
print time.time() - t 

Использование re.findall() также, как представляется, примерно в три раза быстрее, чем JSon парсер, он потребляет около 260 МБ:

import re 
obj = re.compile('{.*?: (\d*?)}') 
with open('datafile.txt', 'r') as f: 
    data = f.read() 
s = set(obj.findall(data)) 
+0

Я пробовал ваш код 're.findall' и да, он увеличивает эффективность времени на огромную сумму. Было интересно отметить такую ​​огромную производительность. Я понял код, но мой вопрос, почему он быстрее?Просьба представить ваше мнение по этому поводу. –

+0

'для этой конкретной задачи, где единственное, что вы делаете, это извлечение баллов' - возможно, это быстрее, потому что не нужно определять и создавать тип объекта python, который представляют (под) строки. – wwii

-2

Попробуйте использовать набор

set([x['score'] for x in scores]) 

Например

>>> scores = [{"score" : 78}, {"score": 65} , {"score" : 65}] 
>>> set([x['score'] for x in scores]) 
set([65, 78]) 
+0

Вы предлагаете, чтобы вопросник использовал точный код, который он задает, как улучшить. Это не очень полезно. – Blckknght

+0

Я использовал генератор. Использование генератора часто считается эффективным. –

+0

Не заметили. Прости. – haki

1

Я не думаю, что есть какой-нибудь способ, чтобы улучшить положение вещей намного. Медленная часть - это, вероятно, только тот факт, что в какой-то момент вам нужно проанализировать весь файл JSON. Независимо от того, делаете ли вы все сначала (с json.load) или понемногу (при потреблении генератора от ijson.items), весь файл должен быть обработан в конце концов.

Преимущество использования ijson заключается в том, что в любой момент времени вам нужно иметь небольшой объем данных в памяти. Вероятно, это не имеет большого значения для файла с сотней мегабайт данных, но было бы очень важно, если бы ваш файл данных вырос до гигабайта или более. Конечно, это также может зависеть от оборудования, на котором вы работаете. Если ваш код будет запущен во встроенной системе с ограниченной оперативной памятью, ограничение использования памяти значительно важнее. С другой стороны, если он будет работать на высокопроизводительном сервере или рабочей станции с множеством доступных в нем батов, нет никаких оснований для удержания.

Таким образом, если вы не ожидаете, что ваши данные станут слишком большими (относительно емкости вашей системы в ОЗУ), вы можете попробовать протестировать, хотите ли использовать json.load, чтобы прочитать весь файл в начале, а затем получить уникальные значения с set быстрее. Я не думаю, что есть другие очевидные ярлыки.

0

В моей системе простой код ниже обрабатывает 10 000 000 баллов (139 мегабайт) за 18 секунд. Это слишком медленно?

#!/usr/local/cpython-2.7/bin/python 

from __future__ import print_function 

import json # since json file is large, hence making use of ijson 

with open('data_large', 'r') as file_: 
    content = json.load(file_) 
    print(set(element['score'] for element in content)) 
Смежные вопросы