Intuitive understanding of Numpy nd-array
ndarray vs list: both can hold a 1-dimensional collection of elements; however, in an ndarray the elements would usually all be of the same type (e.g., 64-bit floating point numbers), and numpy provides operators (and behind-the-scenes optimizations) for calculations on these vectors. For example, you can (quickly) add elements in nda1 and nda2 via nda3 = nda1 + nda2. With lists, you would need to do lst3 = [a + b for (a, b) in zip(lst1, lst2)]. On the other hand, you can easily insert and remove items in lists. ndarrays are designed for high-performance computations on vectors of numbers; lists are designed for ad hoc operations on arbitrary collections of objects.
ndarray vs dictionary: these are quite dissimilar. Dictionaries allow you to select objects from an arbitrary collection by name; ndarrays usually only hold numbers, and only allow lookup via index number (unless you get into recarrays, which you didn't ask about).  
ndarray vs Pandas dataframe: dataframes are somewhat similar to multidimensional ndarrays, in that they are designed to hold similar types of data in each column. However, different columns of a dataframe would often hold different types of data, while all the elements in a multidimensional ndarray would usually be numbers of the same type. In addition, dataframes provide name-based indexing across rows and columns. I like to think of dataframes as something like a dictionary of 1-dimensional ndarrays, i.e., each column of the dataframe is like a 1-dimensional ndarray, and you can retrieve the column by name and then manipulate it. But Pandas provides additional indexing goodness, so you can also give a name to each row, and then pull elements out of the table based on both their row and column names. Pandas also provides operators for element-wise operations (e.g., adding two columns together), similar to numpy. But it generally does this by matching index terms, not row/column numbers. So data manipulations in Pandas are slower but more reliable.
ndarrays vs structured arrays: structured arrays are somewhat like the rows of a Pandas dataframe (you can have different standardized types of data in each column). But the semantics for manipulating them are more like standard numpy operations -- you have to make sure the right data is in the right spot in the array before you operate on it. (Pandas will re-sort the tables so the row-names match if needed.)
ndarray vs sequence of lists: ndarrays are initialized and displayed like sequences of lists, and if you take the nth element of a 2D array, you get a list (the row). But internally, in an ndarray, every element has the same datatype (unlike lists), and the values are packed tightly and uniformly in memory. This allows processors to quickly perform operations on all the values together. Lists are more like pointers to values stored elsewhere, and mathematical computations on lists or lists-of-lists are not optimized. Also, you can't use 2D or 3D indexing with lists-of-lists (you have to say lst[1][2][3], not lst[1, 2, 3]), nor can you easily do elementwise operations (lst1+lst2 does not do elementwise addition like nda1+nda2).
higher dimensions: you can create an ndarray with any number of dimensions. This is sort of similar to a list of lists of lists. e.g., this makes a 3D array: np.array([[[1, 2], [3, 4]], [[5, 6], [7,8]]])
So I've read the manual - but the structure still comes confusing to me. Specifically, what is the relationship between:

nd-array and Python list?
nd-array and Python dictionary?
nd-array and Pandas DataFrame?
nd-arrays and Numpy "structured arrays"?

Also, is nd-array just like a sequence of lists? 
Where does the "n-dimension" come into the picture? Because it looks just like a matrix, which is just two dimensions.
Thanks!