## Examples using CSV files¶

Parsing comma-separtated-values (CSV) files is a common task. There are many tools available in Python to deal with this. Let's start by using the built-in csv module.

In [147]:
import csv # using Python module


Now, we want to open an example file, and read the contents:

In [148]:
f = open('example_1.csv','rb') # use binary mode if on MS windows
d = [i for i in csv.reader(f) ] # use list comprehension to read from file
f.close() # close file
print d

[['Name', 'DOB', 'Years', 'Degree'], ['Alice Jones', '12/1/1980', '3', 'MS'], ['Bob Smith', '1/1/1969', '4', 'BS'], ['John Book', '5/3/1980', '11', 'BA'], ['Billy Blanks', '6/9/2000', '8', 'AA']]


### Adding new fields as columns¶

This reads the rows of the CSV file into a list-of-lists.

Now, let's suppose we want to create columns for last name and first name instead of having just one name field. The first element in the list d is the header, so we had the additional fields there:

In [149]:
d[0].append('Last Name')
d[0].append('First Name')
print d[0]

['Name', 'DOB', 'Years', 'Degree', 'Last Name', 'First Name']


Now, we want to split the original Name field into first and last names and put these at the ends of their respective rows.

In [150]:
for row in d[1:]: # start at 1st, not 0th column. Each row is a list
first,last= row[0].split() # split on white-space
row.append(last) # append to each row
row.append(first)

print d

[['Name', 'DOB', 'Years', 'Degree', 'Last Name', 'First Name'], ['Alice Jones', '12/1/1980', '3', 'MS', 'Jones', 'Alice'], ['Bob Smith', '1/1/1969', '4', 'BS', 'Smith', 'Bob'], ['John Book', '5/3/1980', '11', 'BA', 'Book', 'John'], ['Billy Blanks', '6/9/2000', '8', 'AA', 'Blanks', 'Billy']]

In [151]:
#%qtconsole


### Writing updated CSV file¶

Now, we want to write out our new data in CSV format

In [152]:
f = open('example_1_out.csv','wb') # write mode binary
fw = csv.writer(f) # create csv writer
fw.writerows(d)
f.close() # close file


Now, opening the file example_1_out.csv using excel (or another reader) should show the new column. That covers the most direct and pure-Python way to dealing with CSV files. However, there are many other tools available. For example, numpy provides power methods to access these files.

## Using Numpy to parse CSV files¶

Let's see how to accomplish the same work as above by using Numpy.

In [153]:
import numpy as np

print d
print d.dtype

[['Name' 'DOB' 'Years' 'Degree']
['Alice Jones' '12/1/1980' '3' 'MS']
['Bob Smith' '1/1/1969' '4' 'BS']
['John Book' '5/3/1980' '11' 'BA']
['Billy Blanks' '6/9/2000' '8' 'AA']]
|S12


Notice that we did not have to use open to get at the contents of the file. By default, the delimiter is any whitespace, so we had to change this to the comma character. The dtype specifies we want everything to be read in as a string. Numpy can figure out how long that string needs to be as it goes through the file so we don't have to specify that ahead of time (we probably don't know it anyway). In this case, the dtype turns out to be a twelve character string S12. Note that this is the maximum length is used for all strings so there is obviously a lot of extra space if most of the strings are short and just a few are long.

Numpy provides many more ways of reading data via the dtype. For example,

In [154]:
dt = [('name',   'S64'),   # The first element of the tuple is our name for each respective column
('dob',    'S64'),   # and the second element is the numpy dtype we want for that column.
('years',  'int'),   # Here we want years as an integer, not a string
('degree', 'S64'), ]

print d

[('Alice Jones', '12/1/1980', 3, 'MS') ('Bob Smith', '1/1/1969', 4, 'BS')
('John Book', '5/3/1980', 11, 'BA') ('Billy Blanks', '6/9/2000', 8, 'AA')]


The advantage of doing it this way is that now we can compute the years column using numpy tools. For example, here is the mean of the years.

In [155]:
print d['years'].mean() # using numpy arrays

6.5


Now to get back to the main task at hand: splitting the name field into first and last name.

In [156]:
import string

n=map(string.split,d['name'])
w=array([tuple(i)+tuple(j) for i,j in zip(d,n)],    # list comprehension glues tuple-ized rows together
dtype=dt+[('first','S64'),('last','S64')]) # append new dtypes to existing list of dtypes


That was kind of non-simple, but now we can write this to a CSV using savetxt.

In [157]:
# the comments are set to '' to avoid hash marks on the first line.


Now, you can inspect the so-generated file and verify it is a CSV.

## Using pandas to parse CSV files¶

pandas is the real power tool for this job.

In [158]:
import pandas as pd

print d
print type(d)

           Name        DOB  Years Degree
0   Alice Jones  12/1/1980      3     MS
1     Bob Smith   1/1/1969      4     BS
2     John Book   5/3/1980     11     BA
3  Billy Blanks   6/9/2000      8     AA
<class 'pandas.core.frame.DataFrame'>


Now, we have read the CSV file as a pandas DataFrame which is a super-structure that sits on top of numpy. Let's examine the columns of this DataFrame.

In [159]:
print d.columns

Index([Name, DOB, Years, Degree], dtype=object)


Notice that there is an extra space after the Name. This potentially makes it hard to access the columns using pandas slicing. For example,

In [161]:
print d.DOB # this works great when the column header name has no spaces in it.
print d['Name'] # you can also refer to columns using this syntax

0    12/1/1980
1     1/1/1969
2     5/3/1980
3     6/9/2000
Name: DOB, dtype: object
0     Alice Jones
1       Bob Smith
2       John Book
3    Billy Blanks
Name: Name, dtype: object


Luckily, this is not hard to fix. We just need to create another column that is free of these trailing spaces:

In [ ]:
d['name']=d['Name '] # easily create extra column
print d.name         # now you can access this column using this syntax


Pandas is a lot more powerful than this! We can parse the columns by types individually by providing a dtype for each column as a dictionary.

In [ ]:
d = pd.read_csv('example_1.csv',dtype={'Name ':'S64','DOB':'S64','Years':int,'Degree':'S64'})
print d


Now, we can compute along the columns as we did before with numpy.

In [ ]:
print d.Years.mean()


You can also parse the DOB field to get a true timestamp instead of a string using the parse_dates keyword.

In [171]:
d = pd.read_csv('example_1.csv',dtype={'Name':'S64',
'DOB':'S64',
'Years':int,
'Degree':'S64'},parse_dates=[1])


Now, we can compute with these datetime objects as in the following.

In [164]:
# difference in birthdays between Alice Jones and John Book
print d.DOB[0] -  d.DOB[2]

212 days, 0:00:00


Now we now how many days are between the respective birthdays of Alice Jones and John Book.

In [ ]:
%qtconsole

In [166]:
d['first']=map(lambda x:string.split(x)[0],d['Name'])
d['last']=map(lambda x:string.split(x)[1],d['Name'])
print d

           Name                 DOB  Years Degree  first    last
0   Alice Jones 1980-12-01 00:00:00      3     MS  Alice   Jones
1     Bob Smith 1969-01-01 00:00:00      4     BS    Bob   Smith
2     John Book 1980-05-03 00:00:00     11     BA   John    Book
3  Billy Blanks 2000-06-09 00:00:00      8     AA  Billy  Blanks

In [167]:
print d

           Name                 DOB  Years Degree  first    last
0   Alice Jones 1980-12-01 00:00:00      3     MS  Alice   Jones
1     Bob Smith 1969-01-01 00:00:00      4     BS    Bob   Smith
2     John Book 1980-05-03 00:00:00     11     BA   John    Book
3  Billy Blanks 2000-06-09 00:00:00      8     AA  Billy  Blanks


## Inject into a sqlite database¶

In [170]:
import pandas.io.sql as pd_sql
import sqlite3 as sql # sqlite3 is built into Python

con = sql.connect("example_1.db")
pd_sql.write_frame(d,'data',con) # write to DB as table named "data"
con.close()

In [ ]: