2012-08-29 7 views
2

Я читаю csv по строкам. CSV выглядит так:слегка искаженные данные, равные

29.781646 
29.781646 
42.698079 
43.346914 
44.369203 
45.006459 
45.006459 
39.316758 

Когда два числа точно такие же, я хотел бы немного изменить его.

Например, есть два значения, которые 29.781646, и я хотел бы изменить один, чтобы быть 29.781645

Если CSV содержит:

29.781646 
29.781646 
29.781646 

, то я хотел бы изменить его на:

29.781646 
29.781645 
29.781644 

Я был бы очень признателен за ваше руководство по эффективному внедрению.

Пожалуйста, обратите внимание, что я хочу сделать это в упаковке 0.000001

+0

ли вам всегда хочется уменьшить значение? – deadly

+0

@deadly это не имеет значения для меня, если они разные –

+0

Хорошо. И вы хотите записать числа обратно в файл CSV? – deadly

ответ

6

Вы можете просто перебирать файл построчно, и следить видел значений с помощью set, уменьшая значение, если она уже в set.

грубый пример:

seen = set() 
with open('test.csv') as input, open('test_out.csv', 'w') as output: 
    for line in input: 
     value = float(line) 
     while value in seen: 
      value -= 0.000001 
     seen.add(value) 
     output.write(str(value) + '\n') 

Это ЭФФЕКТИВНАЯ поскольку set предлагает O (1) поиск


Если вы собираетесь записать значения обратно в тот же файл в любом случае, вы можете использовать модуль FileInput:

import fileinput 

seen = set() 
for line in fileinput.FileInput('test.csv', inplace=True): 
    value = float(line) 
    while value in seen: 
     value -= 0.000001 
    seen.add(value) 
    print str(value).strip() 

EDIT

Для решения комментарий eumiro по поводу вопроса с плавающей точкой:

Вы можете использовать decimal модули Decimal или просто умножить/разделить значение с/1000000 работать с int вместо использования float. Как я уже писал, это просто грубый пример :-)

+0

Действительно, умный чек. – Emmanuel

+1

Умный чек, к сожалению, не работает, если слишком много «последовательных» номеров. См. Мой комментарий к вопросу. – eumiro

+0

Та же идея может быть использована с множеством, но вместо того, чтобы многократно менять значение в цикле, сохраните исходное значение и вместо этого измените модификатор. –

1
>>> s = """29.781646 
29.781646 
42.698079 
43.346914 
44.369203 
45.006459 
45.006459 
39.316758 
""" 
>>> d = {} 
>>> for nb in [float(l) for l in s.split('\n') if l]: 
    # Create a dict of repetitions, to decrease by the number of times already seen 
    if nb not in d: 
     d[nb] = 0 
     print nb 
    else: 
     rep = d[nb] 
     d[nb] = rep + 1 
     print nb - d[nb] * 0.000001 


29.781646 
29.781645 
42.698079 
43.346914 
44.369203 
45.006459 
45.006458 
39.316758 
>>> 
+0

Ну, нет, это не так, но я скопировал плохой результат (я дважды запускал его без перезагрузки dict :). Результат изменился, спасибо! – Emmanuel

+0

отлично смотрится! можете ли вы объяснить эту строку для nb в [float (l) для l в s.split ('\ n'), если l]: –

1

На основе BigYellowCactus но адреса eumiro Комментарий о том, как накапливаются ошибки в поплавках, которые изменяются во много раз:

seen = set() with open('test.csv') as input, open('test_out.csv', 'w') as output: 
    for line in input: 
     value = float(line) 
     modifier = 1 

     while True 
      new_value = value - (modifier * 0.000001) 
      modifier += 1 
      if not new_value in seen: 
       break 

     seen.add(new_value) 
     output.write(str(value) + '\n') 
Смежные вопросы