Первое решение использует разреженные матрицы в формате координат от scipy (см. coo_matrix ):
from scipy.sparse import coo_matrix
rows, cols, data = zip(*[(row, col, A[row][col]) for row in A for col in A[row]])
coo = coo_matrix((data, (rows, cols)))
>>> coo.toarray()
array([[ 0, 0, 2, 3],
[ 0, 0, 0, 5],
[ 0, 0, 0, 0],
[ 0, 10, 0, 0]])
coo.dot(x)
>>> array([ 5, 5, 0, 10])
Второе решение использует python и numpy только для NaN и для хранения окончательного массива:
rows = range(min(A.keys()), 1 + max(A.keys()))
result = []
for row in rows:
row_data = A.get(row)
result.append(sum(A_val * x[col]
for col, A_val in row_data.iteritems()) # .items() for Python 3
if row_data else np.nan)
Ax = np.array(result)
>>> Ax
array([ 5., 5., nan, 10.])