Проблема с циклами

Наги

Пользователь
Пользователь
Окт 25, 2020
75
5
8
Всем добрый день!
Вопрос следующий. Вот есть у меня 2 списка:
cp = [0, 1, 3, 4, 5, 6]
x = [5, 40, 20, 5, 40, 5]
Мне надо создать новый список result такого вида:
result = [5, 30, 5, 40, 5, 5]
Значения получаются следующим образом:
Смотрим, что между 0 и 1 в списке ср 1 - 0 = 1 значение.
Берем это 1 значение из списка х (5), делим на количество значений (1), получаем 5. Добавляем в result.
Но, если в списке ср между значениями больше 1, т.е. например между 3 и 1: 3 - 1 = 2.
То из списка х надо взять 2 значения (40 и 20) и поделить их сумму на количество значений, т.е. 40 + 20 = 60, 60 / 2 = 30 и 30 занести в result.
Последнее значение в result получается копированием предпоследнего (берем 5, копируем, получается 5 и 5).
Я написала код, который получает первые 2 значения списка. Дальше идут ошибки с индексами и оттого неправильные значения. Собственно, я запуталась с индексами. Помогите, пожалуйста, очень прошу!
Вот код:
Python:
cp = [0, 1, 3, 4, 5, 6]
x = [5, 40, 20, 5, 40, 5]

resids = []
sum = 0
for i, v in enumerate(cp): #тут находим делители чисел из списка х
    if i == 0:
        res = cp[i + 1]
        resids.append(res)
    elif i == len(cp) - 1:
        res = cp[i] - cp[i - 1]
        resids.append(res)
    else:
        res = cp[i + 1] - cp[i]
        resids.append(res)
result = []

for i2, v2 in enumerate(x): # тут пытаемся делить
    for i1, v1 in enumerate(resids):
        if v1 == 1:
            result.append(v2)
        else:
            for i3 in range(1, v1 + 1):
                sum += x[i3]
            result.append(sum / v1)
 

4olshoy_blen

Популярный
Пользователь
Ноя 13, 2022
465
128
43
Странная задача... Как получается 40 в result?
Если это из курса какого-то, желательно показать оригинальное условие
 

Наги

Пользователь
Пользователь
Окт 25, 2020
75
5
8
Странная задача... Как получается 40 в result?
Если это из курса какого-то, желательно показать оригинальное условие
Нет, это не из курса. 40 получается так, что мы берем из х 40, делим на 1, т.к. между 5 и 4 разница 1. Т.е. 40 / 1 = 40. Везде, кроме 3 и 1 там разница между коэффициентами 1. А у 3 и 1 - 2.
 

4olshoy_blen

Популярный
Пользователь
Ноя 13, 2022
465
128
43
Как пример, но мне думается есть более лучшее решение
Python:
cp = [0, 1, 3, 4, 5, 6]
x = [5, 40, 20, 5, 40, 5]
i, j, result = 0, 0, []

while j != len(x) - 1:
    tmp = cp[j+1] - cp[j]
    if tmp > 1:
        result.append(sum(x[i:tmp+1]) // tmp)
        i += tmp
    else:
        result.append(x[i])
        i += 1
    j += 1
else:
    result.append(result[-1])

print(result)
 
  • Мне нравится
Реакции: Наги

Наги

Пользователь
Пользователь
Окт 25, 2020
75
5
8
Как пример, но мне думается есть более лучшее решение
Python:
cp = [0, 1, 3, 4, 5, 6]
x = [5, 40, 20, 5, 40, 5]
i, j, result = 0, 0, []

while j != len(x) - 1:
    tmp = cp[j+1] - cp[j]
    if tmp > 1:
        result.append(sum(x[i:tmp+1]) // tmp)
        i += tmp
    else:
        result.append(x[i])
        i += 1
    j += 1
else:
    result.append(result[-1])

print(result)
Спасибо огромное!! Единственное, я попробовала еще это на других данных, более длинных и вот такая ошибка:
IndexError: index 10 is out of bounds for axis 0 with size 10
Не пойму почему, ведь данные такие же по структуре, только длиннее.
Список x там - это третья колонка, а сp = [0, 247, 249, 252, 255, 276, 277, 319, 332, 501]
Данные приложила..
 

Вложения

  • data_n8.txt
    32 КБ · Просмотры: 1
Последнее редактирование:

4olshoy_blen

Популярный
Пользователь
Ноя 13, 2022
465
128
43
Единственное, я попробовала еще это на других данных, более длинных
А как считывались данные для списка х?
 

Наги

Пользователь
Пользователь
Окт 25, 2020
75
5
8
Вот полный код. Он довольно длинный, но вся работа идет только в def create_and_visualise().
Python:
import numpy as np
import pylab as pl


def create_and_visualise(name):
    x = []
    t1 = []
    t2 = []
    tbins = []
    xbins = []
    xplot = []

    with open(name, 'r') as f:
        for line in f:
            data_list = line.split()

            t1.append(float(data_list[0]))
            t2.append(float(data_list[1]))
            x.append(float(data_list[2]))
            tbins.append(float(data_list[0]))
            xplot.append(float(data_list[2]))

    tbins.append(t2[-1])
    xplot.append(x[-1])

    edges, change_points = bayesian_blocks(t1, np.array(tbins), x)
    print(f'{edges=}')
    print(f'{change_points=}')

    i, j, result = 0, 0, []

    while j != len(x) - 1:
        tmp = change_points[j + 1] - change_points[j]
        if tmp > 1:
            result.append(sum(x[i:tmp + 1]) // tmp)
            i += tmp
        else:
            result.append(x[i])
            i += 1
        j += 1
    else:
        result.append(result[-1])

    print(result)

    pl.step(tbins, xplot, where='post')
    pl.step(edges, result, where='post')
    pl.show()


def bayesian_blocks(t, tb, x):
    # copy and sort the array
    t = np.sort(t)
    N = t.size

    # create length-(N + 1) array of cell edges
    edges = tb
    block_length = t[-1] - edges

    # arrays needed for the iteration
    best = np.zeros(N, dtype=float)
    last = np.zeros(N, dtype=int)

    # -----------------------------------------------------------------
    # Start with first data cell; add one cell at each iteration
    # -----------------------------------------------------------------
    for K in range(N):
        # Compute the width and count of the final bin for all possible
        # locations of the K^th changepoint
        width = block_length[:K + 1] - block_length[K + 1]
        count_vec = np.cumsum(x[:K + 1][::-1])[::-1]

        # evaluate fitness function for these possibilities
        fit_vec = count_vec * (np.log(count_vec / width) - 1)
        fit_vec -= 4  # 4 comes from the prior on the number of changepoints
        fit_vec[1:] += best[:K]

        # find the max of the fitness: this is the K^th changepoint
        i_max = np.argmax(fit_vec)
        last[K] = i_max
        best[K] = fit_vec[i_max]

    # -----------------------------------------------------------------
    # Recover changepoints by iteratively peeling off the last block
    # -----------------------------------------------------------------
    change_points = np.zeros(N, dtype=int)
    i_cp = N
    ind = N
    while True:
        i_cp -= 1
        change_points[i_cp] = ind
        if ind == 0:
            break
        ind = last[ind - 1]
    change_points = change_points[i_cp:]

    return edges[change_points], change_points


def create_and_show():
    create_and_visualise('data_n8.txt')


if __name__ == '__main__':
    create_and_show()
 

4olshoy_blen

Популярный
Пользователь
Ноя 13, 2022
465
128
43
В списке х содержится 501 элемент, тогда как в change_points только 10, отсюда и ошибка. В начальном примере оба списка были одинаковой длины. Пофиксить можно поменяв х на change_points в условии цикла while: while j != len(change_points) - 1:. Но я все равно пока не понимаю что происходит в коде и что вообще требуется сделать.
А зачем создавать лишнюю функцию create_and_show? Можно же сразу вызвать create_and_visualise...
но вся работа идет только в def create_and_visualise()
Тут тоже спорный момент... bayesian_blocks вызывается внутри create_and_visualise, значит работа не только в ней
 

Наги

Пользователь
Пользователь
Окт 25, 2020
75
5
8
В списке х содержится 501 элемент, тогда как в change_points только 10, отсюда и ошибка. В начальном примере оба списка были одинаковой длины. Пофиксить можно поменяв х на change_points в условии цикла while: while j != len(change_points) - 1:. Но я все равно пока не понимаю что происходит в коде и что вообще требуется сделать.
А зачем создавать лишнюю функцию create_and_show? Можно же сразу вызвать create_and_visualise...

Тут тоже спорный момент... bayesian_blocks вызывается внутри create_and_visualise, значит работа не только в ней
Так ну... возьмем на этом паузу. Это уже продвижение. Благодарю! И еще напишу.
 
  • Мне нравится
Реакции: 4olshoy_blen

Наги

Пользователь
Пользователь
Окт 25, 2020
75
5
8
В списке х содержится 501 элемент, тогда как в change_points только 10, отсюда и ошибка. В начальном примере оба списка были одинаковой длины. Пофиксить можно поменяв х на change_points в условии цикла while: while j != len(change_points) - 1:. Но я все равно пока не понимаю что происходит в коде и что вообще требуется сделать.
А зачем создавать лишнюю функцию create_and_show? Можно же сразу вызвать create_and_visualise...

Тут тоже спорный момент... bayesian_blocks вызывается внутри create_and_visualise, значит работа не только в ней
Все-таки спрошу еще. Можно ли оставить тут: while j != len(change_points) - 1: х, не менять на change_points и убрать ошибку?
 

4olshoy_blen

Популярный
Пользователь
Ноя 13, 2022
465
128
43
while j != len(x[:10]) - 1:
 

Наги

Пользователь
Пользователь
Окт 25, 2020
75
5
8
Извините, что продолжаю надоедать. Я придумала пример, который показывает, где ошибка. Код не меняла (там while j != len(change_points) - 1:), заново кидать не буду. А пример во вложении. Код сейчас судя по всему неправильно работает в конце. Там, где change_points 4 и 8. Там 4 значения: 5, 5, 15, 5. Значит, в результате должно быть 5 + 5 + 15 + 5 = 30 / 4 = 7.5. А там сейчас 1.0. Я думаю, если с этим разобраться, то везде все станет хорошо у меня..
 

Вложения

  • data_test.txt
    107 байт · Просмотры: 2

4olshoy_blen

Популярный
Пользователь
Ноя 13, 2022
465
128
43
Распишите полный алгоритм действий, скажем для первых 10 чисел. Из вашего скудного примера я скорее что-то не учел
 

Наги

Пользователь
Пользователь
Окт 25, 2020
75
5
8
Распишите полный алгоритм действий, скажем для первых 10 чисел. Из вашего скудного примера я скорее что-то не учел
Пишу для первой версии данных:
cp = [0, 1, 3, 4, 5, 6]
x = [5, 40, 20, 5, 40, 5]
1. Рассматриваем первую пару (интервал) чисел: 0 и 1 из списка cp.
2. Вычисляем длину интервала: 1 - 0 = 1.
3. Берем первое число (оно соответствует первому интервалу из cp) из списка х: 5. Берем его одно, так как интервал единичный.
4. Делим 5 на длину интервала: 1: 5 / 1 = 5.
5. Заносим 5 в новый список result.
То есть смысл в том, чтобы находить длины интервалов в cp и на них делить суммы чисел из х.
Далее:
6. Рассматриваем вторую пару чисел в ср: 1 и 3. Вычисляем длину этого интервала: 3 - 1 = 2. Так как интервал НЕ единичный, а имеет длину 2, берем 2 следующих числа из х: 40 и 20. Находим их сумму: 40 + 20 = 60. Делим на длину интервала: 60 / 2 = 30. Заносим это число в result.
7. Рассматриваем следующую пару чисел в ср: 3 и 4. Находим длину интервала: 4 - 3 = 1. Интервал снова единичный, поэтому из х берем одно число, следующее не использовавшееся еще: 5. Снова это число (в случае не единичного интервала это была бы сумма) делим на длину интервала: 5 / 1 = 5. Заносим в result.
8. Рассматриваем следующую пару чисел в ср: 4 и 5. Находим длину интервала: 5 - 4 = 1. Интервал снова единичный, поэтому из х берем одно число, следующее не использовавшееся еще: 40. Снова это число делим на длину интервала: 40 / 1 = 40. Заносим в result.
9. Рассматриваем следующую пару чисел в ср: 5 и 6. Находим длину интервала: 6 - 5 = 1. Интервал снова единичный, поэтому из х берем одно число, следующее не использовавшееся еще: 5. Снова это число делим на длину интервала: 5 / 1 = 5. Заносим в result.
10. Пары чисел в ср кончились. Дублируем последнее число, занесенное в result еще раз в result. Это число было 5. Дублируем его, получаем в конце списка result 5, 5.

Если рассматривать последнюю версию данных:
cp = [0, 1, 4, 8]
x = [5, 40, 20, 50, 5, 5, 15, 5]
То тут для 0 -1 тоже самое, затем:
1. Рассматриваем пару чисел в ср: 4 и 1. Находим длину интервала: 4 - 1 = 3. Интервал НЕ единичный, поэтому из х берем столько чисел, какой длины интервал: 3, Это: 40, 20, 50. Суммируем их: 40 + 20 + 50 = 110. Это число делим на длину интервала: 110 / 3 = 36,6. Заносим в result.
2. Рассматриваем пару чисел в ср: 8 и 4. Находим длину интервала: 8 - 4 = 4. Интервал НЕ единичный, поэтому из х берем столько чисел, какой длины интервал: 4, Это: 5, 5, 15, 5. Суммируем их: 5 + 5 + 15 + 5 = 30. Это число делим на длину интервала: 30 / 4 = 7,5. Заносим в result.

Я вчера еще посидела над кодом, возможно неточность в том, что в sum(x[i:tmp + 1]) i может быть больше tmp+ 1.
 

4olshoy_blen

Популярный
Пользователь
Ноя 13, 2022
465
128
43
возможно неточность в том, что в sum(x[i:tmp + 1])
да, неточность тут, но дело не в больше или меньше, а вместо 1 нужно i, т.е. sum(x[i:tmp + i])

Список x там - это третья колонка, а сp = [0, 247, 249, 252, 255, 276, 277, 319, 332, 501]
С исправленной суммой для этих данных result у меня вышел [4.0, 24.0, 45.0, 27.0, 18.0, 39.0, 16.0, 8.0, 4.0, 4.0]. Это верный результат?
 
  • Мне нравится
Реакции: Наги

4olshoy_blen

Популярный
Пользователь
Ноя 13, 2022
465
128
43
result.append(sum(x[i:tmp+1]) // tmp)
и если не нужно целочисленное деление, то нужно убрать одну /, но тогда округлить до нужного знака
 

Наги

Пользователь
Пользователь
Окт 25, 2020
75
5
8
да, неточность тут, но дело не в больше или меньше, а вместо 1 нужно i, т.е. sum(x[i:tmp + i])


С исправленной суммой для этих данных result у меня вышел [4.0, 24.0, 45.0, 27.0, 18.0, 39.0, 16.0, 8.0, 4.0, 4.0]. Это верный результат?
Да! Это очень похоже на правду! *_* Я еще уточню, так как правильного ответа у меня нет. Но, надеюсь, на этом все. ОГРОМНОЕ спасибо)
 

Наги

Пользователь
Пользователь
Окт 25, 2020
75
5
8
и если не нужно целочисленное деление, то нужно убрать одну /, но тогда округлить до нужного знака
Спасибо, это я понимаю) И, если потребуется, смогу сама сделать)
 
  • Мне нравится
Реакции: 4olshoy_blen

Форум IT Специалистов