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.