Python NumPy: How to Save NumPy Arrays to CSV in Python
Exporting NumPy arrays to CSV files enables data sharing with spreadsheets, other programs, and collaborators. NumPy and Pandas each offer methods suited to different requirements.
Using np.savetxt() - Pure NumPy
The simplest approach for numeric data without dependencies:
import numpy as np
arr = np.array([
[1.234, 5.678],
[9.012, 3.456]
])
np.savetxt('data.csv', arr, delimiter=',', fmt='%.2f')
Result in data.csv:
1.23,5.68
9.01,3.46
Formatting Options
import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6]])
# Default format (scientific notation)
np.savetxt('default.csv', arr, delimiter=',')
# 1.000000000000000000e+00,2.000000000000000000e+00,3.000000000000000000e+00
# 4.000000000000000000e+00,5.000000000000000000e+00,6.000000000000000000e+00
# Integer format
np.savetxt('integers.csv', arr, delimiter=',', fmt='%d')
# 1,2,3
# 4,5,6
# Two decimal places
np.savetxt('floats.csv', arr, delimiter=',', fmt='%.2f')
# 1.00,2.00,3.00
# 4.00,5.00,6.00
# Mixed formats per column
np.savetxt('mixed.csv', arr, delimiter=',', fmt=['%d', '%.1f', '%.3f'])
# 1,2.0,3.000
# 4,5.0,6.000
Adding Headers and Comments
import numpy as np
arr = np.array([[1, 100], [2, 200], [3, 300]])
np.savetxt(
'with_header.csv',
arr,
delimiter=',',
fmt='%d',
header='ID,Value',
comments='' # Remove default '# ' prefix
)
Result:
ID,Value
1,100
2,200
3,300
Without comments='', NumPy adds a # prefix to the header line, which can confuse some CSV parsers.
Using Pandas - With Column Headers
Best for labeled data that needs to be shared:
import pandas as pd
import numpy as np
arr = np.array([
[1, 100, 10.5],
[2, 200, 20.3],
[3, 300, 30.1]
])
df = pd.DataFrame(arr, columns=['ID', 'Value', 'Rate'])
df.to_csv('report.csv', index=False)
Result in report.csv:
ID,Value,Rate
1.0,100.0,10.5
2.0,200.0,20.3
3.0,300.0,30.1
Controlling Data Types
import pandas as pd
import numpy as np
arr = np.array([[1, 100], [2, 200], [3, 300]])
df = pd.DataFrame(arr, columns=['ID', 'Value'])
# Keep integers as integers
df['ID'] = df['ID'].astype(int)
df['Value'] = df['Value'].astype(int)
df.to_csv('clean.csv', index=False)
Result:
ID,Value
1,100
2,200
3,300
Adding Row Labels
import pandas as pd
import numpy as np
arr = np.array([[85, 90], [78, 88], [92, 95]])
df = pd.DataFrame(
arr,
columns=['Math', 'Science'],
index=['Alice', 'Bob', 'Charlie']
)
df.to_csv('scores.csv', index_label='Student')
Result:
Student,Math,Science
Alice,85,90
Bob,78,88
Charlie,92,95
Binary Format - For Speed
When data stays within Python/NumPy, binary formats are much faster:
import numpy as np
arr = np.random.rand(1000, 1000)
# Save to binary (.npy)
np.save('data.npy', arr)
# Load back
loaded = np.load('data.npy')
print(np.array_equal(arr, loaded)) # True
Multiple Arrays
import numpy as np
x = np.array([1, 2, 3])
y = np.array([4, 5, 6])
# Save multiple arrays (.npz)
np.savez('multiple.npz', x=x, y=y)
# Load
data = np.load('multiple.npz')
print(data['x']) # [1 2 3]
print(data['y']) # [4 5 6]
# Compressed version
np.savez_compressed('compressed.npz', x=x, y=y)
Performance Comparison
import numpy as np
import pandas as pd
import timeit
arr = np.random.rand(10000, 100)
# CSV with np.savetxt
def save_numpy():
np.savetxt('test_np.csv', arr, delimiter=',')
# CSV with pandas
def save_pandas():
pd.DataFrame(arr).to_csv('test_pd.csv', index=False)
# Binary with np.save
def save_binary():
np.save('test.npy', arr)
print(f"np.savetxt: {timeit.timeit(save_numpy, number=5):.2f}s")
print(f"pandas: {timeit.timeit(save_pandas, number=5):.2f}s")
print(f"np.save: {timeit.timeit(save_binary, number=5):.4f}s")
Typical output:
np.savetxt: 8.52s
pandas: 4.31s
np.save: 0.08s
Binary .npy files are 50-100x faster than CSV and preserve exact precision. Use CSV only when you need human readability or compatibility with other tools.
Loading CSV Files
Read CSV files back into NumPy arrays:
import numpy as np
# Load with NumPy (numeric data only)
arr = np.loadtxt('data.csv', delimiter=',')
# Skip header row
arr = np.loadtxt('with_header.csv', delimiter=',', skiprows=1)
# Load with Pandas (more flexible)
import pandas as pd
df = pd.read_csv('report.csv')
arr = df.values # or df.to_numpy()
Handling Different Data Types
String Data
import numpy as np
# String array needs special handling
names = np.array(['Alice', 'Bob', 'Charlie'])
scores = np.array([85, 90, 78])
# Combine and save
combined = np.column_stack([names, scores])
np.savetxt('names.csv', combined, delimiter=',', fmt='%s')
# Better: use Pandas for mixed types
import pandas as pd
df = pd.DataFrame({'Name': names, 'Score': scores})
df.to_csv('names_pd.csv', index=False)
Complex Numbers
import numpy as np
# Complex numbers need special handling
complex_arr = np.array([1+2j, 3+4j, 5+6j])
# Save real and imaginary parts separately
np.savetxt(
'complex.csv',
np.column_stack([complex_arr.real, complex_arr.imag]),
delimiter=',',
header='real,imag',
comments=''
)
Summary
| Method | Speed | Headers | Best For |
|---|---|---|---|
np.savetxt() | Medium | Manual | Raw numeric data |
| Pandas | Medium | ✅ Easy | Labeled, shareable data |
np.save() | ⚡ Fast | N/A | Internal storage |
| Format | Human Readable | Precision | File Size |
|---|---|---|---|
| CSV | ✅ Yes | Limited | Large |
.npy | ❌ No | Exact | Medium |
.npz compressed | ❌ No | Exact | Small |
Use np.savetxt() for simple numeric exports, Pandas when you need headers and compatibility with spreadsheets, and .npy binary format for internal storage where speed and precision matter.