Lesson 7.5
Reading CSV files
CSV files
Now that we are familiar with reading and writing simple files, let us see how to handle slightly more complex files. CSV files1 are quite common in data science.In a CSV file, adjacent values in each line are separated by commas. A CSV file looks like this:
Such files are a good choice for representing tabular data. For the rest of this lesson, we will assume that CSV files are used to represent some such tabular data. The first line in the file is called the header. The header gives information about the fields or columns in the data. The rest of the lines can be treated as rows in the data. If this file is represented as a table, it would look like this:
col0 | col1 | col2 | col3 |
---|---|---|---|
row1 | item11 | item12 | item13 |
row2 | item21 | item22 | item23 |
row3 | item31 | item32 | item33 |
row4 | item41 | item42 | item43 |
row5 | item51 | item52 | item53 |
Reading a CSV file
Let us create a CSV file in Replit and name it table.csv
:
Opening and reading a CSV file is no different from opening a text file. Let us try to print the lines in the file:
This is the output we get:
So far so good. Now that we are able to extract the lines from the file, let us start asking some questions.
Print the chemistry marks scored by the students, one in each line.
This requires us to extract the last column from the file. How do we do this? Consider any one line in the file, say the second one:
This is a string that corresponds to one row in the file. If we need to separate it into different columns, we need to use the split()
method and split the line based on a comma:
This returns a list of strings:
To extract the last column, we just need to take the last element from this list and convert it into an integer:
That is all! We have done this for one row. We need to do this for all the rows. Enter loop:
Aha, but we get an error:
Traceback (most recent call last):
File "main.py", line 5, in <module>
chem_marks = int(columns[-1])
ValueError: invalid literal for int() with base 10: 'Chemistry'
Can you see why? We have tried to convert the last column of the header into an integer as well. The moral of the story is that when we are reading CSV files, we need to find a way to deal with the header. Let us modify our code towards that end:
This works! In the second line, we read the header. Now, when the for loop starts in line 5, we are ready to read from the second line in the file. Consider the following approach that uses the readlines()
method alone:
f = open('table.csv', 'r')
lines = f.readlines()
# lines[1: ] is the rest of the list
# after ignoring the header
for line in lines[1: ]:
line = line.strip() # strip the line of \n
columns = line.split(',') # split based on comma
chem_marks = int(columns[-1]) # convert last column to int
print(chem_marks)
f.close()
readlines()
is a reasonable choice for reading small files, say under 1000 lines. We get all the lines of the files in a list. Reading a file reduces to processing a list of strings. If lines
is the list of lines, then lines[i]
corresponds to the \((i + 1)^{th}\) line in the file. Going the other way, the \(i^{th}\) line in the file corresponds to the string lines[i - 1]
.
Processing large files
When it comes to large files, readline()
is the best method to use. Processing large files is best done by reading one line at a time. Using readlines()
for large files is a dangerous idea. This is because, readlines()
dumps the entire content of the file into a list of strings. When the file is large, this list will occupy a large amount of memory. Let us try to write the same program given above using the readline
method:
Files to Collections
It is often useful to convert a CSV file and store in a suitable collection. We could do this in several ways. Here, let us try to create the following list of dictionaries from the file:
data = [
{'Name': 'Newton', 'Physics': 100, 'Mathematics': 98, 'Chemistry': 90},
{'Name': 'Einstein', 'Physics': 100, 'Mathematics': 85, 'Chemistry': 88},
{'Name': 'Ramanujan', 'Physics': 70, 'Mathematics': 100, 'Chemistry': 70},
{'Name': 'Gauss', 'Physics': 100, 'Mathematics': 100, 'Chemistry': 70}]
Couple of points to note.
- This is a list of dictionaries. Each dictionary in the list corresponds to one row in the file.
- The elements in the header appear as keys in every dictionary.
- The values of the dictionary are of different data types. Names are strings, marks are integers.
This is going to be a fairly long code. Let us break it down. First, some basic processing to get the list of lines from the file after stripping them of the trailing newlines:
Next, let us get the details of the header:
Now, it is time to go through the remaining lines in the file: