First because your question asks about giving names to arrays, I feel obligated to point out that using "structured arrays" for the purpose of giving names is probably not the best approach. We often like to give names to rows/columns when we're working with tables, if this is the case I suggest you try something like pandas which is awesome. If you simply want to organize some data in your code, a dictionary of arrays is often much better than a structured array, so for example you can do:
Y = {'ID':X[0], 'Ring':X[1]}
With that out of the way, if you want to use a structured array, here is the clearest way to do it in my opinion:
import numpy as np
RING = [1,2,2,3,3,3]
ID = [1,2,3,4,5,6]
X = np.array([ID, RING])
dt = {'names':['ID', 'Ring'], 'formats':[int, int]}
Y = np.zeros(len(RING), dtype=dt)
Y['ID'] = X[0]
Y['Ring'] = X[1]
Answer from Bi Rico on Stack OverflowFirst because your question asks about giving names to arrays, I feel obligated to point out that using "structured arrays" for the purpose of giving names is probably not the best approach. We often like to give names to rows/columns when we're working with tables, if this is the case I suggest you try something like pandas which is awesome. If you simply want to organize some data in your code, a dictionary of arrays is often much better than a structured array, so for example you can do:
Y = {'ID':X[0], 'Ring':X[1]}
With that out of the way, if you want to use a structured array, here is the clearest way to do it in my opinion:
import numpy as np
RING = [1,2,2,3,3,3]
ID = [1,2,3,4,5,6]
X = np.array([ID, RING])
dt = {'names':['ID', 'Ring'], 'formats':[int, int]}
Y = np.zeros(len(RING), dtype=dt)
Y['ID'] = X[0]
Y['Ring'] = X[1]
store-different-datatypes-in-one-numpy-array another page including a nice solution of adding name to an array which can be used as column Example:
r = np.core.records.fromarrays([x1,x2,x3],names='a,b,c')
# x1, x2, x3 are flatten array
# a,b,c are field name
The correct data input form for a structured array is a list of tuples:
In [71]: signal = [(1,2,3),(2,3,1),(3,2,1)]
...: col_names = ('left','right','center')
...: signal = np.array(signal, dtype = [(n, 'int16') for n in col_names])
In [72]:
In [72]: signal
Out[72]:
array([(1, 2, 3), (2, 3, 1), (3, 2, 1)],
dtype=[('left', '<i2'), ('right', '<i2'), ('center', '<i2')])
1.16 has added a couple of functions that make it easier to convert to and from structured arrays:
In [73]: import numpy.lib.recfunctions as rfn
In [74]: signal = np.array([[1,2,3],[1,2,3],[1,2,3]])
In [75]: dt = np.dtype([(n, 'int16') for n in col_names])
In [76]: dt
Out[76]: dtype([('left', '<i2'), ('right', '<i2'), ('center', '<i2')])
In [77]: rfn.unstructured_to_structured(signal, dt)
Out[77]:
array([(1, 2, 3), (1, 2, 3), (1, 2, 3)],
dtype=[('left', '<i2'), ('right', '<i2'), ('center', '<i2')])
Applying this dt to signal has a problem:
In [82]: signal.view(dt)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-82-f0fa01ce8128> in <module>
----> 1 signal.view(dt)
ValueError: When changing to a smaller dtype, its size must be a divisor of the size of original dtype
We can get around that by first converting signal to a compatible dtype:
In [83]: signal.astype('i2').view(dt)
Out[83]:
array([[(1, 2, 3)],
[(1, 2, 3)],
[(1, 2, 3)]],
dtype=[('left', '<i2'), ('right', '<i2'), ('center', '<i2')])
But note that Out[83] shape is (3,1). The other arrays were shape (3,). view has always had this shape problem when converting to/from structured arrays. That's part of why the newer functions are easier to use.
values = [(1,2,3),(1,2,3),(1,2,3)]
signal = np.array(values, [('left', '<i2'), ('center', '<i2'), ('right', '<i2')])
signal['right']
array([3, 3, 3], dtype=int16)
With pandas.DataFrame.to_csv you can write the columns and the index to a file:
import numpy as np
import pandas as pd
A = np.random.randint(0, 10, size=36).reshape(6, 6)
names = [_ for _ in 'abcdef']
df = pd.DataFrame(A, index=names, columns=names)
df.to_csv('df.csv', index=True, header=True, sep=' ')
will give you the following df.csv file:
a b c d e f
a 1 5 5 0 4 4
b 2 7 5 4 0 9
c 6 5 6 9 7 0
d 4 3 7 9 9 3
e 8 1 5 1 9 0
f 2 8 0 0 5 1
Numpy will handle n-dimensional arrays fine, but many of the facilities are limited to 2-dimensional arrays. Not even sure how you want the output file to look.
Many people who would wish for named columns overlook the recarray() capabilities of numpy. Good stuff to know, but that only "names" one dimension.
For two dimensions, Pandas is very cool.
In [275]: DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])],
.....: orient='index', columns=['one', 'two', 'three'])
Out[275]:
one two three
A 1 2 3
B 4 5 6
If output is the only problem you are trying to solve here, I'd probably just stick with a few lines of hand coded magic as it will be less weighty than installing another package for one feature.
Maybe this can help (if you don't want to use numpy):
headers = ['foo', 'bar', 'baz', 'other']
l = len(headers)
arr = [["xxx" for i in range(l)] for j in range(l)]
# adding top row
arr = [headers] + arr
# adding first column
headers_mod = ['Title'] + headers
new_arr = [[headers_mod[i]]+arr[i] for i in range(l+1)]
for i in new_arr:
print(*i)
gives you the output as:
Title foo bar baz other
foo xxx xxx xxx xxx
bar xxx xxx xxx xxx
baz xxx xxx xxx xxx
other xxx xxx xxx xxx
Otherwise, when dealing with array manipulations in python try going with numpy, pandas, as they provide better operations like by giving option for axis, transpose, etc.
numpy is excellent for tables, but for a labeled table like this pandas might be better for your needs.
Solution using numpy:
import numpy as np
# The header that i want to add
headers = ['foo', 'bar', 'baz', 'other']
ll = len(headers)+1
data = [['xxx' for _ in range(ll)] for j in range(ll)]
data = np.array(data, dtype=object)
data[0,0] = 'Title'
data[0,1:] = headers
data[1:,0] = headers
print(data)
prints
[['Title' 'foo' 'bar' 'baz' 'other']
['foo' 'xxx' 'xxx' 'xxx' 'xxx']
['bar' 'xxx' 'xxx' 'xxx' 'xxx']
['baz' 'xxx' 'xxx' 'xxx' 'xxx']
['other' 'xxx' 'xxx' 'xxx' 'xxx']]
Setting dtype to object allows your array to mix strings and other data types you might want to use. If your data is just strings then you can use 'UN' as the dtype, where N is the longest string you plan to use. (Numpy, when making an all string array automatically picks your longest string as the maximum length for the strings, which is fine unless your strings are all shorter than the headers you plan to add.)
Alternate version of the above code:
import numpy as np
# The header that i want to add
headers = ['foo', 'bar', 'baz', 'other']
# Add Title to headers to simply later assignment
headers = ['Title'] + headers
ll = len(headers)
data = [['xxx' for _ in range(ll)] for j in range(ll)]
data = np.array(data)
data[0,:] = headers
data[:,0] = headers
print(data)
pandas, on the other hand, is explicitly designed to handle headers
import numpy as np, pandas as pd
# The header that i want to add
headers = ['foo', 'bar', 'baz', 'other']
ll = len(headers) + 1
data = [['xxx' for _ in range(ll)] for j in range(ll)]
data = np.array(data)
data = pd.DataFrame(data[1:,1:], columns=headers, index=headers)
data.columns.name = 'Title'
data.loc['foo','bar'] = 'yes'
print(data)
print('')
print(data['bar'])
print('')
print(data.loc['foo',:])
prints
Title foo bar baz other
foo xxx yes xxx xxx
bar xxx xxx xxx xxx
baz xxx xxx xxx xxx
other xxx xxx xxx xxx
foo yes
bar xxx
baz xxx
other xxx
Name: bar, dtype: object
Title
foo xxx
bar yes
baz xxx
other xxx
Name: foo, dtype: object
The problem is that you are thinking in terms of spreadsheet-like arrays, whereas NumPy does use different concepts.
Here is what you must know about NumPy:
- NumPy arrays only contain elements of a single type.
- If you need spreadsheet-like "columns", this type must be some tuple-like type. Such arrays are called Structured Arrays, because their elements are structures (i.e. tuples).
In your case, NumPy would thus take your 2-dimensional regular array and produce a one-dimensional array whose type is a 108-element tuple (the spreadsheet array that you are thinking of is 2-dimensional).
These choices were probably made for efficiency reasons: all the elements of an array have the same type and therefore have the same size: they can be accessed, at a low-level, very simply and quickly.
Now, as user545424 showed, there is a simple NumPy answer to what you want to do (genfromtxt() accepts a names argument with column names).
If you want to convert your array from a regular NumPy ndarray to a structured array, you can do:
data.view(dtype=[(n, 'float64') for n in csv_names]).reshape(len(data))
(you were close: you used astype() instead of view()).
You can also check the answers to quite a few Stackoverflow questions, including Converting a 2D numpy array to a structured array and how to convert regular numpy array to record array?.
Unfortunately, I don't know what is going on when you try to add the field names, but I do know that you can build the array you want directly from the file via
data = np.genfromtxt(csv_file, delimiter=',', names=True)
EDIT:
It seems like adding field names only works when the input is a list of tuples:
data = np.array(map(tuple,data), [(n, 'float64') for n in csv_names])
NumPy structured arrays have named columns:
import numpy as np
a = range(100)
A = np.array(list(zip(*[iter(a)] * 2)), dtype=[('C1', 'int32'),('C2', 'int64')])
print(A.dtype)
[('C1', '<i4'), ('C2', '<i8')]
You can access the columns by name like this:
print(A['C1'])
# [ 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48
# 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98]
Note that using np.array with zip causes NumPy to build an array from a temporary list of tuples. Python lists of tuples use a lot more memory than equivalent NumPy arrays. So if your array is very large you may not want to use zip.
Instead, given a NumPy array A, you could use ravel() to make A a 1D
array, and then use view to turn it into a structured array, and then use astype to convert the columns to the desired type:
a = range(100)
A = np.array(a).reshape( len(a)//2, 2)
A = A.ravel().view([('col1','i8'),('col2','i8'),]).astype([('col1','i4'),('col2','i8'),])
print(A[:5])
# array([(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)],
# dtype=[('col1', '<i4'), ('col2', '<i8')])
print(A.dtype)
# dtype([('col1', '<i4'), ('col2', '<i8')])
I know this is an old question, but a more recently available option would be to try using pandas. The DataFrame type is designed for structured data like this, where columns are named and can be of different types.
You are trying to create a Record Array/Structured Array, you can checkout numpy.core.records.fromrecords -
In [35]: data = np.core.records.fromrecords([[1.], [2.], [3.]],names=['Time'])
In [36]: data
Out[36]:
rec.array([(1.0,), (2.0,), (3.0,)],
dtype=[('Time', '<f8')])
In [37]: data['Time']
Out[37]: array([ 1., 2., 3.])
Like this ?
data = numpy.array([(1,), (2,), (3,)], dtype=[('Time', float)])
See also this usefull module to manipulate Record Array