Skip to main content

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
note

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
tip

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​

MethodSpeedHeadersBest For
np.savetxt()MediumManualRaw numeric data
PandasMedium✅ EasyLabeled, shareable data
np.save()⚡ FastN/AInternal storage
FormatHuman ReadablePrecisionFile Size
CSV✅ YesLimitedLarge
.npy❌ NoExactMedium
.npz compressed❌ NoExactSmall

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.