NumPy Input and Output: Complete Guide to Reading and
Saving Data
When we work with NumPy, creating an
array is only one part of the job.
In real projects, data usually comes
from files, CSV files, text files, databases, sensors, or other applications.
After processing the data, we also need to save the results.
NumPy provides several functions for
reading and writing data.
In this tutorial, we will learn
NumPy Input and Output, commonly called NumPy I/O, from beginner to advanced level.
We will cover:
- Saving arrays using np.save()
- Loading arrays using np.load()
- Saving multiple arrays using np.savez()
- Using compressed .npz files
- Reading text and CSV files
- Writing text and CSV files
- Using np.loadtxt()
- Using np.savetxt()
- Understanding np.genfromtxt()
- Handling missing data
- Selecting columns
- Assigning column names
- Converting data while reading
- Using masked arrays
- Practical examples
- Exercises
1. What is NumPy I/O?
I/O means Input and Output.
Input means bringing data into your
Python program.
Output means saving data from your
Python program.
For example:
import
numpy as np
data
= np.array([10, 20, 30, 40, 50])
The array currently exists in
memory.
If the program ends, the array will
normally disappear.
If we want to use it later, we can
save it to a file.
The basic flow is:
NumPy Program
|
-----------------------
| |
Input
Output
| |
Read data Save data
| |
CSV / TXT / NPY NPY / NPZ / TXT
NumPy supports several formats for
storing and reading arrays.
2. Main NumPy I/O Functions
Some important NumPy I/O functions
are:
|
Function |
Purpose |
|
np.save() |
Save one NumPy array |
|
np.load() |
Load NumPy data |
|
np.savez() |
Save multiple arrays |
|
np.savez_compressed() |
Save multiple arrays in compressed
form |
|
np.loadtxt() |
Read simple text or CSV data |
|
np.savetxt() |
Write arrays to text files |
|
np.genfromtxt() |
Read text data with more control
and missing-value support |
|
np.fromfile() |
Read raw binary or text data |
|
np.ndarray.tofile() |
Write array data directly to a
file |
The most commonly used functions for
beginners are:
save()
load()
savetxt()
loadtxt()
genfromtxt()
savez()
3. Saving a NumPy Array with np.save()
The np.save() function is useful when we want to store a NumPy array in
NumPy's binary .npy
format.
Basic syntax:
np.save(file,
array)
Example:
import
numpy as np
marks
= np.array([78, 85, 92, 67, 88])
np.save("marks.npy",
marks)
This creates:
marks.npy
The .npy format is designed specifically for NumPy arrays.
It preserves important information
about the array, such as its data type and shape.
4. Loading an Array with np.load()
After saving an array, we can
retrieve it using np.load().
Example:
import
numpy as np
marks
= np.load("marks.npy")
print(marks)
Output:
[78
85 92 67 88]
The basic pattern is:
np.save("data.npy",
data)
data
= np.load("data.npy")
This is very useful when a program
needs to save its results and use them later.
5. Saving a Two-Dimensional Array
NumPy can save multidimensional
arrays as well.
Example:
import
numpy as np
marks
= np.array([
[78, 85, 92],
[67, 88, 76],
[90, 95, 89]
])
np.save("student_marks.npy",
marks)
Load it again:
data
= np.load("student_marks.npy")
print(data)
Output:
[[78
85 92]
[67 88 76]
[90 95 89]]
The shape is retained.
print(data.shape)
Output:
(3,
3)
6. Why Use the NPY Format?
The .npy format is especially useful when the data is going to be
used again by NumPy.
For example:
Python
program
|
v
NumPy
array
|
v
student_marks.npy
|
v
Later
Python program
|
v
NumPy
array
It is generally more convenient for
NumPy-to-NumPy data exchange than manually creating a text file.
7. Saving Multiple Arrays with np.savez()
Sometimes one project contains
several arrays.
For example:
students
= np.array(["Asha", "Rahul", "Kiran"])
marks
= np.array([85, 91, 78])
attendance
= np.array([90, 95, 88])
Instead of creating three separate
files, we can store them together.
Use:
np.savez()
Example:
np.savez(
"student_data.npz",
students=students,
marks=marks,
attendance=attendance
)
This creates:
student_data.npz
8. Loading an NPZ File
We can load the file using:
data
= np.load("student_data.npz")
The stored arrays can be accessed by
their names.
print(data["students"])
print(data["marks"])
print(data["attendance"])
This makes .npz files useful for storing related arrays together.
9. np.savez_compressed()
Large datasets can consume
considerable storage space.
NumPy also provides:
np.savez_compressed()
Example:
np.savez_compressed(
"student_data_compressed.npz",
marks=marks,
attendance=attendance
)
The resulting file is compressed.
Use compressed storage when reducing
file size is important.
10. NPY vs NPZ
A simple way to remember the
difference is:
.npy
|
+-- Usually one NumPy array
.npz
|
+-- Multiple NumPy arrays
Example:
np.save("marks.npy",
marks)
For multiple arrays:
np.savez(
"data.npz",
marks=marks,
attendance=attendance
)
11. Reading Text Files with np.loadtxt()
Not every dataset is stored as .npy.
Many datasets are available as:
.txt
.csv
For simple numeric text data, we can
use:
np.loadtxt()
Suppose marks.txt contains:
78
85 92
67
88 76
90
95 89
We can read it using:
import
numpy as np
data
= np.loadtxt("marks.txt")
print(data)
Output:
[[78.
85. 92.]
[67. 88. 76.]
[90. 95. 89.]]
12. Reading CSV Data with loadtxt()
CSV means Comma-Separated Values.
Suppose students.csv contains:
78,85,92
67,88,76
90,95,89
We can specify the comma as the
delimiter.
data
= np.loadtxt("students.csv", delimiter=",")
The delimiter tells NumPy how columns are separated.
For CSV:
delimiter=","
For tab-separated data:
delimiter="\t"
13. Writing Data with np.savetxt()
The opposite operation is writing an
array to a text file.
Use:
np.savetxt()
Example:
import
numpy as np
marks
= np.array([
[78, 85, 92],
[67, 88, 76],
[90, 95, 89]
])
np.savetxt("marks.txt",
marks)
This writes the array into a text
file.
14. Creating a CSV File with savetxt()
We can also specify a comma
delimiter.
np.savetxt(
"marks.csv",
marks,
delimiter=","
)
The resulting file will contain
values separated by commas.
15. Adding a Header
A header can make a text or CSV file
easier to understand.
Example:
np.savetxt(
"marks.csv",
marks,
delimiter=",",
header="Maths,Science,Computer"
)
The resulting file will contain a
header followed by the data.
16. Controlling Number Formatting
Suppose we have decimal values:
data
= np.array([
[12.34567, 45.67891],
[23.45678, 67.89123]
])
We can control how numbers are
written.
np.savetxt(
"values.txt",
data,
fmt="%.2f"
)
The format:
%.2f
means that two digits should be
displayed after the decimal point.
17. When loadtxt() Is Not Enough
loadtxt() works well when the input data is clean and regular.
But real-world datasets are often
messy.
For example:
78,85,92
67,,76
90,95,89
One value is missing.
Another dataset might contain:
78,N/A,92
67,85,?
90,95,89
Now we need more control.
This is where:
np.genfromtxt()
becomes useful.
18. Introduction to np.genfromtxt()
genfromtxt() is designed for importing tabular text data when more
flexibility is required.
It can help with:
- Different delimiters
- Missing values
- Headers
- Selecting columns
- Different data types
- Named columns
- Custom conversion functions
- Fixed-width data
A simple example:
import
numpy as np
data
= np.genfromtxt(
"students.csv",
delimiter=","
)
19. How genfromtxt() Processes Data
A useful way to understand genfromtxt() is to imagine two stages.
Text
file
|
v
Split
each line into values
|
v
Convert
values to required data types
|
v
NumPy
array
This additional processing gives genfromtxt() more flexibility than simpler input functions.
20. Using String Data Instead of a File
genfromtxt() can also work with data supplied directly by Python.
For example:
from
io import StringIO
import
numpy as np
data
= "10,20,30\n40,50,60"
result
= np.genfromtxt(
StringIO(data),
delimiter=","
)
print(result)
Output:
[[10.
20. 30.]
[40. 50. 60.]]
This is useful when data is already
available as a string.
21. The delimiter Parameter
The delimiter tells NumPy how to separate columns.
For comma-separated data:
delimiter=","
For tab-separated data:
delimiter="\t"
For space-separated data, we can
often leave the delimiter unspecified.
Example:
data
= "10 20 30\n40 50 60"
result
= np.genfromtxt(
StringIO(data)
)
NumPy can split the values based on
whitespace.
22. Fixed-Width Data
Not every text file uses commas or
spaces.
Sometimes each column occupies a
fixed number of characters.
For example:
001002003
004005006
We can specify the width of each
field.
Example:
data
= "123456789\n987654321"
result
= np.genfromtxt(
StringIO(data),
delimiter=3
)
print(result)
Here each column is three characters
wide.
We can also specify different
widths:
delimiter=(4,
3, 2)
This is useful for fixed-width
files.
23. Removing Extra Spaces with autostrip
Consider:
1, Alice,
85
2, Rahul,
91
Extra spaces can become part of the
imported strings.
We can use:
autostrip=True
Example:
result
= np.genfromtxt(
StringIO(data),
delimiter=",",
dtype="U10",
autostrip=True
)
This tells NumPy to remove
unnecessary spaces around the values.
24. Ignoring Comments
Many data files contain comments.
For example:
#
Student data
78,85,92
67,88,76
90,95,89
By default, # is treated as a comment marker.
Example:
data
= np.genfromtxt(
"marks.csv",
delimiter=","
)
Comment lines are ignored.
Comments can also appear after data.
For example:
78,85,92
# first student
The comment portion can be ignored.
25. Changing the Comment Character
The comment character can be
customized.
For example:
np.genfromtxt(
"data.txt",
delimiter=",",
comments=";"
)
Now ; is treated as the beginning of a comment.
26. Skipping Header Lines
Many files begin with a title or
header.
Example:
Student
Marks Report
78,85,92
67,88,76
90,95,89
We may want to skip the first line.
Use:
data
= np.genfromtxt(
"marks.csv",
delimiter=",",
skip_header=1
)
skip_header=1 means:
Skip
the first line
Read
the remaining data
27. Skipping Footer Lines
Sometimes unwanted information
appears at the end of the file.
Example:
78,85,92
67,88,76
90,95,89
End
of report
We can skip the last line:
data
= np.genfromtxt(
"marks.csv",
delimiter=",",
skip_footer=1
)
28. Selecting Specific Columns
Suppose the file contains:
101
85 90
102
78 88
103
92 95
Perhaps we only need the first and
last columns.
We can use:
data
= np.genfromtxt(
StringIO(text),
usecols=(0, 2)
)
Remember that NumPy uses zero-based
indexing.
Therefore:
Column
0 = first column
Column
1 = second column
Column
2 = third column
29. Selecting Columns by Name
If column names are available, we
can also use their names.
Example:
data
= np.genfromtxt(
StringIO(text),
names="id,maths,science",
usecols=("id",
"science")
)
This can make the code easier to
understand.
30. Choosing the Data Type
The dtype parameter controls how imported data is represented.
For example:
data
= np.genfromtxt(
StringIO("10 20 30\n40 50 60"),
dtype=np.int64
)
The resulting values are integers.
We can also specify different types
for different columns.
Example:
dtype=(np.int64,
np.float64, np.float64)
This is useful when a dataset
contains different kinds of values.
31. Using dtype=None
Sometimes we do not know the data
type of each column in advance.
We can use:
dtype=None
NumPy will try to determine suitable
types from the data.
Example:
data
= np.genfromtxt(
StringIO("10 Alice\n20 Rahul"),
dtype=None,
names=True
)
However, automatic type detection
requires additional processing.
If performance is important and the
data types are known, explicitly specifying dtype is generally preferable.
32. Giving Names to Columns
Column names are very useful when
working with structured data.
Example:
data
= np.genfromtxt(
StringIO("101 85\n102 91"),
names="id,marks"
)
Now we can access fields using their
names.
For example:
print(data["id"])
print(data["marks"])
This is easier to understand than
remembering column positions.
33. Reading Names from the File
Suppose the input itself contains
column names:
id
marks
101
85
102
91
103
78
We can use:
data
= np.genfromtxt(
StringIO(text),
names=True
)
NumPy reads the first appropriate
line as the field names.
34. The defaultfmt Parameter
When structured data needs names but
some names are not supplied, NumPy can generate default field names.
For example:
f0
f1
f2
We can customize the generated names
using defaultfmt.
Example:
data
= np.genfromtxt(
StringIO("10 20 30"),
dtype=(int, float, int),
defaultfmt="value_%02i"
)
This can produce names such as:
value_00
value_01
value_02
35. Validating Column Names
Column names should be valid and
should not create confusion with Python or NumPy attributes.
For example, names containing spaces
or certain special characters may need to be cleaned.
genfromtxt() provides options such as:
deletechars
excludelist
case_sensitive
These options give more control over
field names.
36. deletechars
deletechars specifies characters that should be removed from field
names.
This is useful when imported column
names contain unwanted special characters.
37. excludelist
Some names may conflict with
existing Python or NumPy names.
For example:
print
file
return
The excludelist option can be used to protect against such conflicts.
38. case_sensitive
We can control the capitalization of
field names.
For example:
case_sensitive=True
keeps the names case-sensitive.
Other settings can convert names to
upper or lower case.
39. Converting Values While Reading
Sometimes the values in a file are
not directly suitable for the required data type.
Consider:
101,25%
102,78.5%
103,91%
The percentage values are strings
because of %.
We can create a converter.
Example:
convert_percent
= lambda x: float(x.strip("%")) / 100
Then:
data
= np.genfromtxt(
StringIO(text),
delimiter=",",
converters={1: convert_percent}
)
Now:
25% -> 0.25
78.5%
-> 0.785
91% -> 0.91
40. Why Are Converters Useful?
Converters are useful when the input
format needs transformation.
Examples include:
25% -> 0.25
2026/09/21
-> date value
"
45 " -> 45
special
text -> numeric value
The converter receives the original
value and returns the desired representation.
41. Converters Can Be Specified by Column Name
If the data has named columns, we do
not always need to use the column number.
For example:
converters={"percentage":
convert_percent}
This can make the code easier to
read.
42. Handling Missing Data
Missing data is common in real-world
datasets.
Example:
101,85,90
102,,88
103,92,95
The second student's second value is
missing.
Another dataset may use:
N/A
?
???
to indicate missing values.
This is one of the important reasons
to use genfromtxt().
43. The missing_values Parameter
We can tell NumPy which values
should be considered missing.
Example:
data
= np.genfromtxt(
StringIO(text),
delimiter=",",
missing_values="N/A"
)
We can also define different missing
markers for different columns.
For example:
missing_values={
0: "N/A",
1: "???"
}
44. The filling_values Parameter
Finding a missing value is only one
part of the problem.
We may also want to replace it with
a particular value.
This is where:
filling_values
is useful.
Example:
data
= np.genfromtxt(
StringIO(text),
delimiter=",",
missing_values="N/A",
filling_values=0
)
Missing values will be replaced
according to the specified filling rule.
45. Default Filling Values
If we do not specify filling_values, NumPy chooses a default based on the expected data type.
For example:
Boolean -> False
Integer -> -1
Float -> np.nan
Complex -> np.nan+0j
String -> ???
This is important because the
default value may not always be appropriate for your application.
For example, replacing a missing
student mark with -1
may be technically valid but may not be suitable for statistical calculations.
Therefore, choose filling values
carefully.
46. Column-Specific Missing Values
Different columns may use different
missing-value markers.
Example:
N/A,85,???
90,
,95
We can define rules for each column.
Example:
missing_values
= {
0: "N/A",
1: " ",
2: "???"
}
And then define the replacement
values:
filling_values
= {
0: 0,
1: 0,
2: -999
}
This gives fine control over messy
datasets.
47. Keeping Track of Missing Values with usemask
Sometimes replacing missing data is
not what we want.
We may want to know exactly which
values were missing.
For this purpose, we can use:
usemask=True
Example:
data
= np.genfromtxt(
StringIO(text),
delimiter=",",
usemask=True
)
NumPy returns a masked array.
The mask identifies positions where
values were missing.
Conceptually:
Data:
10 20
missing
30 40
50
Mask:
False
False True
False
False False
This is useful when missing values
must remain identifiable during later processing.
48. A Complete genfromtxt Example
Let us combine several concepts.
Suppose our data is:
#
Student data
101,85,90
102,N/A,88
103,92,95
We can write:
import
numpy as np
from
io import StringIO
text
= """# Student data
101,85,90
102,N/A,88
103,92,95
"""
data
= np.genfromtxt(
StringIO(text),
delimiter=",",
dtype=np.float64,
missing_values="N/A",
filling_values=0
)
print(data)
The program:
- Reads the text.
- Uses comma as the separator.
- Ignores the comment.
- Detects N/A as missing.
- Replaces the missing value with 0.
- Creates a NumPy array.
49. Choosing the Right NumPy I/O Function
A simple decision guide is useful.
Need
to save one NumPy array?
|
+---- np.save()
Need
to load a .npy/.npz file?
|
+---- np.load()
Need
to save multiple arrays?
|
+---- np.savez()
Need
compression?
|
+---- np.savez_compressed()
Simple
clean text data?
|
+---- np.loadtxt()
Write
array to text/CSV?
|
+---- np.savetxt()
Messy
text data or missing values?
|
+---- np.genfromtxt()
50. Practical Student Marks Project
Suppose we have:
import
numpy as np
marks
= np.array([
[85, 90, 78],
[76, 88, 92],
[91, 84, 89]
])
Save the data:
np.save("marks.npy",
marks)
Load it:
loaded_marks
= np.load("marks.npy")
Save it as CSV:
np.savetxt(
"marks.csv",
marks,
delimiter=",",
fmt="%d"
)
Load the CSV:
data
= np.loadtxt(
"marks.csv",
delimiter=","
)
This demonstrates the difference
between NumPy's binary format and a human-readable text format.
51. Binary Files vs Text Files
There are two important approaches.
Binary
NumPy format
Examples:
.npy
.npz
Advantages:
- Designed for NumPy data
- Preserves array information
- Convenient for NumPy applications
- Suitable for storing arrays for later processing
Text
format
Examples:
.txt
.csv
Advantages:
- Easy for humans to read
- Easy to inspect with a text editor
- Convenient for exchanging simple tabular data
- Widely supported by other applications
The choice depends on the
application.
52. Example: Saving Multiple Arrays
Suppose we have:
names
= np.array(["Asha", "Rahul", "Kiran"])
marks
= np.array([85, 91, 78])
attendance
= np.array([90, 95, 88])
Store them together:
np.savez(
"class_data.npz",
names=names,
marks=marks,
attendance=attendance
)
Load:
data
= np.load("class_data.npz")
print(data["names"])
print(data["marks"])
print(data["attendance"])
53. Example: Reading Selected Columns
Suppose:
101
85 90 95
102
78 88 91
103
92 95 89
If we only need student ID and the
final mark:
data
= np.genfromtxt(
StringIO(text),
usecols=(0, 3)
)
This avoids loading unnecessary
columns into the resulting array.
54. Example: Cleaning Percentage Data
Suppose:
101,85%,90%
102,78%,88%
103,92%,95%
We can convert percentage strings:
def
percentage(value):
return float(value.strip("%"))
Then:
data
= np.genfromtxt(
StringIO(text),
delimiter=",",
converters={
1: percentage,
2: percentage
}
)
Now the percentage columns are
numeric.
55. Common Mistakes
Mistake
1: Forgetting the delimiter
For CSV files:
np.loadtxt("data.csv")
may not interpret the data correctly
if commas separate the columns.
Use:
np.loadtxt(
"data.csv",
delimiter=","
)
Mistake
2: Using loadtxt() for messy data
If the file contains missing values
such as:
10,20,30
40,,60
genfromtxt() is usually more appropriate.
Mistake
3: Forgetting zero-based indexing
For:
A
B C D
the NumPy column indexes are:
A
-> 0
B
-> 1
C
-> 2
D
-> 3
Therefore:
usecols=(0,
3)
selects A and D.
Mistake
4: Ignoring data types
If a dataset contains integers,
floating-point values, and strings, think carefully about the appropriate dtype.
Mistake
5: Replacing missing values without thinking
For example:
filling_values=0
is convenient, but zero may have a
completely different meaning from "missing".
Choose replacement values according
to the problem.
56. Mini Project: Student Dataset Import
Create a file named:
students.csv
with:
101,Asha,85,90
102,Rahul,78,88
103,Kiran,92,95
104,Meena,N/A,91
Try to:
- Read the file using genfromtxt().
- Use comma as the delimiter.
- Give names to the columns.
- Identify N/A as missing.
- Replace missing marks with 0.
- Select only the student ID and marks columns.
- Save the cleaned data as a .npy file.
- Load the .npy file again.
- Print the final array.
57. Exercises
Exercise
1: Save and Load
Create this array:
numbers
= np.array([10, 20, 30, 40, 50])
Save it as:
numbers.npy
Then load it and print the result.
Exercise
2: Multiple Arrays
Create:
names
= np.array(["A", "B", "C"])
marks
= np.array([80, 90, 85])
Save both arrays into:
students.npz
Load the file and display both
arrays.
Exercise
3: CSV File
Create:
marks
= np.array([
[80, 90],
[75, 85],
[92, 88]
])
Save it as:
marks.csv
Use a comma as the delimiter.
Then load the CSV file again.
Exercise
4: Skip Header
Consider:
Student
Marks
80
90
75
85
92
88
Use genfromtxt() to skip the first line.
Exercise
5: Select Columns
Consider:
101
80 90 85
102
75 85 88
103
92 88 91
Read only:
Student
ID
Final
mark
Use usecols.
Exercise
6: Missing Values
Consider:
101,80,90
102,N/A,88
103,92,91
Use genfromtxt() to:
- detect N/A
- replace it with 0
Exercise
7: Percentage Converter
Consider:
101,80%
102,75%
103,92%
Create a converter that changes:
80%
-> 80
75%
-> 75
92%
-> 92
Exercise
8: Column Names
Create an array using:
ID
Name
Marks
Read the data with column names and
access the marks using the field name.
Exercise
9: Masked Array
Create data containing missing
values.
Use:
usemask=True
Print the data and investigate which
elements are masked.
Exercise
10: Mini Data Processing Project
Create a CSV file containing:
ID,Maths,Science,Computer
101,85,90,95
102,78,N/A,88
103,92,95,91
104,N/A,82,89
Write a NumPy program that:
- Reads the file.
- Handles the missing values.
- Assigns column names.
- Selects the three subject columns.
- Calculates the average.
- Saves the processed array as .npy.
- Loads the saved file.
- Displays the final result.
58. Quick Revision
The most important functions are:
np.save()
np.load()
np.savez()
np.savez_compressed()
np.loadtxt()
np.savetxt()
np.genfromtxt()
Remember:
.npy
|
+-- NumPy binary array
.npz
|
+-- Collection of NumPy arrays
.txt
/ .csv
|
+-- Human-readable text data
For simple clean numerical files:
np.loadtxt()
For more complicated text files:
np.genfromtxt()
For saving NumPy arrays:
np.save()
For loading NumPy arrays:
np.load()
59. Final Takeaway
NumPy I/O is an important skill for
anyone working with data.
Creating an array is only the
beginning. A practical program must also know how to read data from external
sources and save processed results.
Start with these four functions:
np.save()
np.load()
np.loadtxt()
np.savetxt()
Then learn:
np.genfromtxt()
when you begin working with
real-world datasets containing headers, comments, different delimiters, missing
values, or inconsistent formats.
Once you understand these functions,
you can build Python programs that move smoothly between files and NumPy
arrays.
The key idea is simple:
External
Data
|
v
Read
with NumPy
|
v
NumPy
Array
|
v
Process
Data
|
v
Save
Results
|
v
.npy
/ .npz / .txt / .csv
This forms an important foundation
for data analysis, machine learning, scientific computing, and engineering
applications using Python and NumPy.
Practice. Experiment. Build.
Try every example yourself instead
of only reading the code. Small experiments with different file formats,
delimiters, missing values, and data types will make NumPy I/O much easier to
understand.
Comments
Post a Comment