2015-09-18 2 views
1

Я хотел бы заполнить массив 24 x 4 данными из формулы (ов). На основе 4 начальных значений, таких как [0, 0, 2137, 1419], массив должен быть заполнен цифрами в соответствии с приведенной ниже таблицей.Python array: формулы для заполнения массива данными

В Excel это легко, когда используется время от времени. Но когда часто используется и с изменением значений в a, b, c или d, было бы полезно использовать Python для создания различных массивов.

Вопрос: Как это может быть достигнуто в Python?

Я предполагаю, что вложенные for i in j loops могут выполнять эту работу, но, честно говоря, я потерялся здесь. Помощь высоко ценится.

начально-данные:

a+ и a- использование 7 рядов

b+ и b- использование 5 рядов

a = 0 b = 0 c = 2137 d = 1419 

формулам: Верхняя половина имеет по возрастанию значения и нижнюю половину имеет нисходящие значения. Существует очень логичный порядок, когда поток x + = 1, x = x, x- = 1 и x = x сдвинут между столбцами. Важное примечание: каждая формула относится к ее предыдущему значению в строке над ним.

a = 0 b = 0 c = 2137 d = 1419 

a+=1 b=b  c+=1  d=d   0 
a+=1 b=b  c+=1  d=d   1 
a+=1 b=b  c+=1  d=d   2 
a+=1 b=b  c+=1  d=d   3 
a+=1 b=b  c+=1  d=d   4 
a+=1 b=b  c+=1  d=d   5 
a+=1 b=b  c+=1  d=d   6 (7 for rows is known) 
a=a  b+=1 c=c  d+=d  0 
a=a  b+=1 c=c  d+=d  1 
a=a  b+=1 c=c  d+=d  2 
a=a  b+=1 c=c  d+=d  3 
a=a  b+=1 c=c  d+=d  4 (5 for rows is known) 
a-=a b=b  c-=c  d=d   0 
a-=a b=b  c-=c  d=d   1 
a-=a b=b  c-=c  d=d   2 
a-=a b=b  c-=c  d=d   3 
a-=a b=b  c-=c  d=d   4 
a-=a b=b  c-=c  d=d   5 
a-=a b=b  c-=c  d=d   6 (7 for rows is known) 
a=a  b-=b c=c  d-=d  0 
a=a  b-=b c=c  d-=d  1 
a=a  b-=b c=c  d-=d  2 
a=a  b-=b c=c  d-=d  3 
a=a  b-=b c=c  d-=d  4 (5 for rows is known) 
            Rows  
0  1  2   3   Columns 

Выход:

array = ([0,0,2137,1419], 
[1,0,2138,1419], 
[2,0,2139,1419], 
[3,0,2140,1419], 
[4,0,2141,1419], 
[5,0,2142,1419], 
[6,0,2143,1419], 
[7,0,2144,1419], 
[7,1,2144,1420], 
[7,2,2144,1421], 
[7,3,2144,1422], 
[7,4,2144,1423], 
[7,5,2144,1424], 
[6,5,2143,1424], 
[5,5,2142,1424], 
[4,5,2141,1424], 
[3,5,2140,1424], 
[2,5,2139,1424], 
[1,5,2138,1424], 
[0,5,2137,1424], 
[0,4,2137,1423], 
[0,3,2137,1422], 
[0,2,2137,1421], 
[0,1,2137,1420], 
[0,0,2137,1419]) 
+0

Почему не 'a- = a',' b- = b', 'c- = c' и' d- = d' становятся 0? Я думаю, вы имеете в виду '- = 1' соответственно.Кроме того, у вас есть numpy? – swenzel

ответ

1

Вы не ответили на мой комментарий еще. Но глядя на желаемый результат и текст после Формулы: Я считаю, что вы действительно хотели добавить/вычесть 1, а не сами переменные.

Итак, вы в основном повторно добавляете вектор [1,0,1,0] в первые 7 строк, затем [0,1,0,1] в следующие пять, а затем снова вычитаете то же самое.
Это красиво линейно, поэтому вы можете суммировать их все кумулятивно и применять результаты всегда к первой строке. Это отлично подходит для numpy!

import numpy as np 
import itertools as it 

# first 7 rows add 1 to a and 1 to c 
add1 = np.array([1, 0, 1, 0]) 

# next 5 rows add 1 to b and 1 to d 
add2 = np.array([0, 1, 0, 1]) 

# stack them accordingly 
upper = np.vstack(list(it.chain(it.repeat(add1, 7), 
           it.repeat(add2, 5)))) 

# lower is the negated version of upper 
lower = -upper 

# stack them 
both = np.vstack((upper, 
        lower)) 

# with cumsum we'll get for each row the relative distance to the first row 
# (istead of distance to previous) 
sums = np.cumsum(both, axis=0) 

# prepend 0 vector to retain the the first row 
sums = np.vstack((np.zeros_like(add1), sums)) 

# create the frist row 
l = np.array([0, 0, 2137, 1419]) 

# now just add up row and sums 
result = l+sums 

print(result) 

Это будет очень быстро, также для больших массивов. Если, однако, у вас нет numpy или вы не хотите его устанавливать, вы можете использовать обходные методы zip и map для реализации эквивалентного подхода.

import itertools as it 

def addVecs(a, b): 
    return [e1 + e2 for e1, e2 in zip(a, b)] 


def scaleVec(a, s): 
    return [e*s for e in a] 


# first 7 rows add 1 to a and 1 to c 
add1 = [1, 0, 1, 0] 

# next 5 rows add 1 to b and 1 to d 
add2 = [0, 1, 0, 1] 

# stack them accordingly 
upper = list(it.chain(it.repeat(add1, 7), 
         it.repeat(add2, 5))) 

# lower is the negated version of upper 
lower = list(it.starmap(scaleVec, zip(upper, it.repeat(-1)))) 

# stack them 
both = upper + lower 

# create cumsum to get for each row the relative distance to the first row 
# (istead of distance to previous) 
sums = [[0, 0, 0, 0]] 
for row in both: 
    sums.append(addVecs(sums[-1], row)) 

# the first row 
l = [0, 0, 2137, 1419] 

# now for each row in sums, add it to l 
result2 = list(it.starmap(addVecs, zip(it.repeat(l), sums))) 
for row in result2: 
    print(row) 

Оба результата содержит ваш желаемый результат:

[[ 0 0 2137 1419] 
[ 1 0 2138 1419] 
[ 2 0 2139 1419] 
[ 3 0 2140 1419] 
[ 4 0 2141 1419] 
[ 5 0 2142 1419] 
[ 6 0 2143 1419] 
[ 7 0 2144 1419] 
[ 7 1 2144 1420] 
[ 7 2 2144 1421] 
[ 7 3 2144 1422] 
[ 7 4 2144 1423] 
[ 7 5 2144 1424] 
[ 6 5 2143 1424] 
[ 5 5 2142 1424] 
[ 4 5 2141 1424] 
[ 3 5 2140 1424] 
[ 2 5 2139 1424] 
[ 1 5 2138 1424] 
[ 0 5 2137 1424] 
[ 0 4 2137 1423] 
[ 0 3 2137 1422] 
[ 0 2 2137 1421] 
[ 0 1 2137 1420] 
[ 0 0 2137 1419]] 

Я протестировал производительность обоих подходов на моем ноутбуке. Имея sums, уже построенный, numpy занимает 6,29 мкс и простой питон 29,5 мкс.

+0

Большое спасибо! Ваше предположение было правильным. В вашем решении numPy мне пришлось удалить «list()», и код работал отлично. Тогда простое решение Python останавливается на «обоих» при укладке «itertools.chain object» и «itertools.starmap object». – snahl

+0

Интересно ... Я не знал, что 'vstack' принимает генераторы. Тем не менее, это не должно быть * необходимо *, чтобы удалить «список» оттуда. Какую ошибку вы получили? И вы обязательно должны оставить «list» в простой версии python. Как вы заметили, без него вы получаете объект «chain» и объект «starmap», который является генератором. Вот почему я превратил их в список, вы не можете добавить генераторы, и как только они будут поглощены, вы не сможете повторить их. – swenzel

+0

Ну, я действительно не знаю - я новичок в Python. После консультации с руководством для «np.vstack» я решил изменить эту строку следующим образом: «upper = np.vstack (it.chain (it.repeat (add1, 7), it.repeat (add2, 5))) '. Однако кажется, что это не работает для чистого решения Python. «Цепочный объект» и «объект starmap» застревают, когда они складываются 'both = верхний + нижний'. msg: 'TypeError: неподдерживаемый тип операндов для +: 'itertools.chain' и 'itertools.starmap''. Я работаю в ноутбуке jupyter на машине windows7-64. – snahl

Смежные вопросы