Подстановка отсутствующих значений в Python

Я хочу заменить отсутствующие значения (None) на последнее предыдущее известное значение. Это мой код. Но это не сработает. Любые предложения для лучшего алгоритма?

t = [[1, 3, None, 5, None], [2, None, None, 3, 1], [4, None, 2, 1, None]]
def treat_missing_values(table):
    for line in table:
        for value in line:
            if value == None:
                value = line[line.index(value)-1]
    return table

print treat_missing_values(t)

Ответ 1

Скорее всего, я это сделаю:

>>> def treat_missing_values(table):
...     for line in table:
...         prev = None
...         for i, value in enumerate(line):
...             if value is None:
...                 line[i] = prev
...             else:
...                 prev = value
...     return table
... 
>>> treat_missing_values([[1, 3, None, 5, None], [2, None, None, 3, 1], [4, None, 2, 1, None]])
[[1, 3, 3, 5, 5], [2, 2, 2, 3, 1], [4, 4, 2, 1, 1]]
>>> treat_missing_values([[None, 3, None, 5, None], [2, None, None, 3, 1], [4, None, 2, 1, None]])
[[None, 3, 3, 5, 5], [2, 2, 2, 3, 1], [4, 4, 2, 1, 1]]

Ответ 2

Когда вы выполняете задание в python, вы просто создаете ссылку на объект в памяти. Вы не можете использовать значение для установки объекта в списке, потому что вы фактически делаете ссылку на значение другим объектом в памяти.

Чтобы сделать то, что вы хотите, вам нужно установить прямо в списке по правому индексу.

Как указано, ваш алгоритм не будет работать, если один из внутренних списков имеет None в качестве первого значения.

Итак, вы можете сделать это вот так:

t = [[1, 3, None, 5, None], [2, None, None, 3, 1], [4, None, 2, 1, None]]
def treat_missing_values(table, default_value):
    last_value = default_value
    for line in table:
        for index in xrange(len(line)):
            if line[index] is None:
                line[index] = last_value
            else:
                last_value = line[index]
    return table

print treat_missing_values(t, 0)

Ответ 3

Эта вещь о поиске индекса из значения не будет работать, если список начинается с None или если имеется дублирующее значение. Попробуйте следующее:

def treat(v):
   p = None
   r = []
   for n in v:
     p = p if n == None else n
     r.append(p)
   return r

def treat_missing_values(table):
   return [ treat(v) for v in table ]

t = [[1, 3, None, 5, None], [2, None, None, 3, 1], [4, None, 2, 1, None]]
print treat_missing_values(t)

Это лучше не быть домашним заданием, чувак.

EDIT Функциональная версия для всех вас поклонников FP:

def treat(l):
  def e(first, remainder):
     return [ first ] + ([] if len(remainder) == 0 else e(first if remainder[0] == None else remainder[0], remainder[1:]))
  return l if len(l) == 0 else e(l[0], l[1:])   

Ответ 4

Это потому, что метод index возвращает первое вхождение аргумента, который вы передаете ему. В первой строке, например, line.index(None) всегда будет возвращать 2, поскольку это первое появление None в этом списке.

Попробуйте это вместо:

    def treat_missing_values(table):
        for line in table:
            for i in range(len(line)):
                if line[i] == None:
                    if i != 0:
                        line[i] = line[i - 1]
                    else:
                        #This line deals with your other problem: What if your FIRST value is None?
                        line[i] = 0 #Some default value here
        return table

Ответ 5

Я бы использовал глобальную переменную, чтобы отслеживать последнее действительное значение. И я использовал бы map() для итерации.

t = [[1, 3, None, 5, None], [2, None, None, 3, 1], [4, None, 2, 1, None]]

prev = 0
def vIfNone(x):
    global prev
    if x:
       prev = x
    else:
       x = prev
    return x

print map( lambda line: map( vIfNone, line ), t )

РЕДАКТИРОВАТЬ: Мальволио, здесь. Извините, что писал в вашем ответе, но в комментарии было слишком много ошибок.

  • if x: выйдет из строя для всех значений ложности (в частности, 0 и пустой строки).
  • Изменчивые глобальные значения плохи. Они не являются потокобезопасными и производят другие своеобразные поведения (в этом случае, если список начинается с None, он устанавливается на последнее значение, которое было обработано вашим кодом.
  • Повторная запись x не нужна; prev всегда имеет правильное значение.
  • В общем, такие вещи должны быть обернуты функциями, для именования и для определения области охвата.

Итак:

def treat(n):
    prev = [ None ]
    def vIfNone(x):
        if x is not None:
           prev[0] = x
        return prev[0]
    return map( vIfNone, n )

(Обратите внимание на странное использование prev как закрытой переменной. Оно будет локально для каждого вызова treat и глобального для всех вызовов vIfNone из одного и того же вызова treat, что вам нужно. вероятно, беспокоя причины Python, которые я не понимаю, это должен быть массив.)

Ответ 6

EDIT1

# your algorithm won't work if the line start with None
t = [[1, 3, None, 5, None], [2, None, None, 3, 1], [4, None, 2, 1, None]]
def treat_missing_values(table):
    for line in table:
        for index in range(len(line)):
            if line[index] == None:
                line[index] = line[index-1]
    return table

print treat_missing_values(t)