{ "metadata": { "name": "", "signature": "sha256:772d5540371c3293531c51079dc46dae1d47fcbf17482858cd1a1b59d5a195e4" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Reading and Writing Files\n", "\n", "by David Paredes (<david.paredes@durham.ac.uk>) and James Keaveney (<james.keaveney@durham.ac.uk>)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Two ways of opening a data file\n", "\n", "In python, there are two ways of opening a data file:\n", "\n", "- Using the built in <code>open</code> function\n", "- Using libraries that parse the file, if it has some format\n", "\n", "Usually, we will deal with highly structured files, so the second method will be easier in most cases (in the case of big files this is no longer true).\n", "\n", "In this tutorial, we will overview two modules/functions, <code>numpy.loadtxt</code> and <code>csv</code>, that allow you to get data from comma-separated-value files (csv), where the different data values reside in a file separated by commas, spaces or other delimiters (as the name suggests...)\n", "\n", "## loadtxt\n", "The function <a href=\"http://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html\"><code>numpy.loadtxt</code></a> also present as <code>scipy.loadtxt</code> in the <code>scipy</code> package, is very simple to use. You just use the name of the file in string format (that is, separated by normal or double-quotes) and the output is an array with the contents of the file. \n", "\n", "For example, let's load the information in the file <a href=\"./code/io/csv_example/simpleDataset.csv\">simpleDataset.csv</a> and store it in variable <code>myDataset</code>.\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import numpy #Remember to import the module\n", "myDataset = numpy.loadtxt(\"./code/io/csv_example/simpleDataset.csv\")\n", "print myDataset" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[[ 1. 3.023 ]\n", " [ 2. 5.1 ]\n", " [ 6. 23. ]\n", " [ 6.6 2. ]\n", " [ 8. 9.23 ]\n", " [ 8.1 10.0001]]\n" ] } ], "prompt_number": 75 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The text file contains two columns of numbers separated by one space. By default, the function takes as a delimiter any white space. \n", "If, for example, the values were separated by commas (as in <a href=\"./code/io/csv_example/simpleDatasetComma.txt\">simpleDatasetComma.txt</a>), we would need to specify the variable <code>delimiter</code>, which is a string containing the delimiting character(s)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "myDatasetComma = numpy.loadtxt(\"./code/io/csv_example/simpleDatasetComma.txt\", delimiter=',')\n", "print myDatasetComma" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[[ 1. 3.023 ]\n", " [ 2. 5.1 ]\n", " [ 6. 23. ]\n", " [ 6.6 2. ]\n", " [ 8. 9.23 ]\n", " [ 8.1 10.0001]]\n" ] } ], "prompt_number": 76 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some files contain headers that are not part of the data (see <a href=\"./code/io/csv_example/fileWithHeader.csv\">fileWithHeader.csv</a>). This file contains 3 lines that give information about the data, but that is not data. The header can be skipped by using keyword <code>skiprows</code>" ] }, { "cell_type": "code", "collapsed": false, "input": [ "complicatedDataset = numpy.loadtxt(\"./code/io/csv_example/fileWithHeader.csv\",delimiter=',', skiprows=3)\n", "print complicatedDataset" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[[-0.0836 0.479172 0.00209844 0.202813 ]\n", " [-0.083598 0.479313 0.00194219 0.202813 ]\n", " [-0.083596 0.479313 0.00180156 0.20275 ]\n", " [-0.083594 0.479313 0.00191875 0.20277 ]\n", " [-0.083592 0.478969 0.00184531 0.20275 ]]\n" ] } ], "prompt_number": 77 }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also select which columns to extract from the file with the keyword <code>usecols</code>" ] }, { "cell_type": "code", "collapsed": false, "input": [ "justSomeCols = numpy.loadtxt(\"./code/io/csv_example/fileWithHeader.csv\", \n", " delimiter=',', skiprows=3, usecols=(1,3))\n", "print justSomeCols" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[[ 0.479172 0.202813]\n", " [ 0.479313 0.202813]\n", " [ 0.479313 0.20275 ]\n", " [ 0.479313 0.20277 ]\n", " [ 0.478969 0.20275 ]]\n" ] } ], "prompt_number": 78 }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "You can get more information about <a href=\"http://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html\"><code>numpy.loadtxt</code></a> in the scipy page, or using the <code>help</code> function, as described in the page <a href=\"notebooks/Basics - Help and information.ipynb\">Basics - Help and information</a>." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## csv\n", "\n", "The module <code>csv</code> has a syntax very similar to that of <code>loadtxt</code> but is much more powerful in the sense that it can handle all sorts of data types. The <a href=\"https://docs.python.org/2/library/csv.html\">official documentation</a> states:\n", "\n", "__The lack of a standard (for csv files) means that subtle differences often exist in the data produced and consumed by different applications. These differences can make it annoying to process CSV files from multiple sources.___\n", "\n", "This modules provides classes to read and write tabular data from/to different formats. The most basic example of reading with this module would be:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import csv\n", "with open(\"./code/io/csv_example/simpleDataset.csv\", 'rb') as ultraImportantFile:\n", " importantReader = csv.reader(ultraImportantFile, delimiter=' ')\n", " for row in importantReader:\n", " print row" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "['1', '3.023']\n", "['2', '5.1']\n", "['6', '23']\n", "['6.6', '2']\n", "['8', '9.23']\n", "['8.1', '10.0001']\n" ] } ], "prompt_number": 79 }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you can see (look at the quotation marks), the reader stores the data as a list of strings separated by the delimiter. This is a default, since a lot of csv files can have heterogeneous data. It is possible to use the function <code>float</code> to convert the data to floats (for example), like\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "with open(\"./code/io/csv_example/simpleDataset.csv\", 'rb') as ultraImportantFile:\n", " data = list(csv.reader(ultraImportantFile, delimiter=' '))\n", " print float(data[0][1])\n" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "3.023\n" ] } ], "prompt_number": 80 }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is also possible to give significative names to columns. For example, if the two columns in the file represent \"current\" and \"voltage\", using the DictReader function" ] }, { "cell_type": "code", "collapsed": false, "input": [ "currentData = []\n", "voltData = []\n", "cols = ['current', 'voltage']\n", "with open(\"./code/io/csv_example/simpleDatasetComma.txt\", 'rb') as csvfile:\n", " for row in csv.DictReader(csvfile, fieldnames=cols, delimiter=','):\n", " # Convert non-string data here e.g.:\n", " thiscurrent = float(row['current'])\n", " thisvoltage = float(row['voltage'])\n", " currentData.append(thiscurrent)\n", " voltData.append(thisvoltage)\n", " print currentData, voltData" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[1.0, 2.0, 6.0, 6.6, 8.0, 8.1] [3.023, 5.1, 23.0, 2.0, 9.23, 10.0001]\n" ] } ], "prompt_number": 81 }, { "cell_type": "markdown", "metadata": {}, "source": [ "#File Output\n", "\n", "So far we've looked at reading files in, but occasionally it's useful to be able to save processed data. If the data needs to be human-read, or read again outside of the code it's written in, then outputting as a csv is useful. If this is not the case, for example you run a calculation that takes a long time and you need to save the result so that the next time the program is run you just look the result up instead of re-calculating, then *pickled* (just the binary) data is the easiest format to use. We will give examples of both below." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## CSV writing\n", "\n", "Let's generate some csv data to eventually export:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import numpy as np\n", "\n", "#generate random data\n", "x = np.arange(-10,10,0.01)\n", "y = np.sin(3*x**2)*np.cos(x)**2\n", "\n", "# print the first few lines\n", "print x[0:10], y[0:10]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[-10. -9.99 -9.98 -9.97 -9.96 -9.95 -9.94 -9.93 -9.92 -9.91] [-0.70386913 -0.57965427 -0.24754818 0.17987328 0.55413639 0.74256453\n", " 0.67521336 0.3704655 -0.06997309 -0.49529355]\n" ] } ], "prompt_number": 82 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's write this into a two-column csv file. We write row-by-row so first we need to convert the data into a 2d-array. We do this using the built-in *zip* function:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "xy = zip(x,y)\n", "\n", "# look at the first few lines of this - note the format is different to the previous block\n", "print xy[0:10]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[(-10.0, -0.70386913217899505), (-9.9900000000000002, -0.57965426709639589), (-9.9800000000000004, -0.24754817534860593), (-9.9700000000000006, 0.17987328163207517), (-9.9600000000000009, 0.55413639253598546), (-9.9500000000000011, 0.74256452644996929), (-9.9400000000000013, 0.67521336030495893), (-9.9300000000000015, 0.37046549973305676), (-9.9200000000000017, -0.069973092764842343), (-9.9100000000000019, -0.49529354803092768)]\n" ] } ], "prompt_number": 83 }, { "cell_type": "code", "collapsed": false, "input": [ "import csv\n", "\n", "filename = './code/io/csv_example/csv_write_example.csv'\n", "with open(filename, 'wb') as csvfile:\n", " csv_writer = csv.writer(csvfile,delimiter=',')\n", " \n", " # if header lines are required, they can be written here\n", " header_line = ('Time (ms)', 'Voltage (V)')\n", " csv_writer.writerow(header_line)\n", " \n", " # write main block of data\n", " for xy_line in xy:\n", " csv_writer.writerow(xy_line)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 84 }, { "cell_type": "markdown", "metadata": {}, "source": [ "That's it. More columns can be added simply by zipping more things together, e.g. zip(x,y,z,...). If you want to look at the csv file we just generated, it's <a href=\"./code/io/csv_example/csv_write_example.csv\">here</a>." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Pickle module\n", "\n", "Let's generate some data that takes a while to process. A large 2D-array should do the job nicely for now. Let's plot it as well, while we're on. And for comparison purposes, let's time how long it takes..." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import time\n", "\n", "st = time.clock()\n", "\n", "# make large arrays\n", "x = np.arange(-100,100,0.1)\n", "y = np.arange(-200,200,0.2)\n", "\n", "X,Y = np.meshgrid(x,y)\n", "\n", "Z = np.exp(-(X**2+Y**2)/80**2)*np.cos(np.sqrt(X**2+Y**2)/20)**2\n", "\n", "print 'Elapsed time (ms):', (time.clock() - st)*1e3\n", "plt.imshow(Z)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Elapsed time (ms): 297.011865079\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 85, "text": [ "<matplotlib.image.AxesImage at 0x7cca898>" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\n11+vnHvp0iUMDg6ip6cH165dq8RfvHgRmzdvrrnW+vXr8c47B2fcqHzjTKsr0GTE9hURDz/8cMPK\nCpKKcw5PPPEE1q5di6eeeqoSv2nTJhw9ehQ//vGPcfTo0QpBbNy4Efv378eVK1dw+fJlzJkzBz09\nPQAm1aTjx49j27ZtOHHiBA4dOlRzvbfffrthDYuIiGgRXABvvPGGK5VKbv369W7Dhg1uw4YN7uTJ\nk+7mzZvukUcecffff7/buXOnGx0drZxz6NAht3z5ctff3+/Onj1bib9w4YIbGBhwy5Ytc88//3zo\nshEREQVGyblo4IiIiGgccvPxnLNnz6K/vx8rVqzA4cOHW12durBs2TJ87nOfw8DAADZu3AigPkfB\nvGDPnj1YvHgx1q1bV4lrJ8dHq30HDhxAb28vBgYGMDAwgJMnT1bSitS+ljqutlpUEmzYsMGdOXPG\njYyMuJUrV7rr16+3ukqZsWzZMvef//ynKu7FF1903/nOd9zt27fdvn373E9+8hPnnHPXrl1zK1eu\ndP/85z/d6dOn3cDAQCuqHMTZs2fdW2+95dauXVuJq6c9X/3qV93x48fdjRs33Be/+EV3/vz5u94W\nC1b7Dhw44H72s5/V5C1a+65ever+8pe/OOecu379uvvMZz7jbt68eVeeXy4klQ8//BAAsGXLFixd\nuhRf+cpXCusc55Q2mcVRcHR0tBVV9uKhhx7CvffeWxXXTo6PVvsA2+WhaO1rpeNqLkiFnemA4jrH\nlUolbN26FY8++ih++9vfAkAmR0FJyzNmg+Pj4cOHsXnzZrz44osVoj937lxh23e3HVdzQSrtgj/+\n8Y9455138KMf/QjPPPMM/v3vf8/YUTBvmGl7spzfCuzduxfvv/8+Tp06hX/84x84cuQIALveRWhf\nKxxXc0Eqg4ODuHTpUuX4woULpnNc3rFkyRIAQH9/Px555BH87ne/qzgKAqhxFLx48WLlXHEUzDuy\ntuezn/1sKsfHvGDRokUolUpYuHAh9u3bhxMnTgAoZvtCjqtA855fLkhl4cKFACZngEZGRvD73/8e\nmzZtanGtsuGjjz6qiMrXr1/HqVOnsH379oqj4Mcff1zjKHjq1ClcuXIFp0+frnIUzDPqaY84Pt64\ncQMnTpzI9bO9evUqAKBcLuPYsWPYsWMHgOK1zyU4rjb1+TXS4jwTnD592q1atcotX77c/fznP291\ndTLj8uXLbv369W79+vVu69at7tVXX3XOubocBfOC3bt3uyVLlrju7m7X29vrjh492laOj9K+rq4u\n19vb61599VX3+OOPu3Xr1rnPf/7z7umnn66azStS+1rpuBqd3yIiIhqKXKg/ERER7YNIKhEREQ1F\nJJWIiIiGIpJKREREQxFJJSIioqGIpBIREdFQRFKJiIhoKCKpRERENBT/D8zCBKbXZNN2AAAAAElF\nTkSuQmCC\n", "text": [ "<matplotlib.figure.Figure at 0x78a2780>" ] } ], "prompt_number": 85 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ok, 4 million points (2k x 2k) takes a little while to process. Let's save that as a csv, and then save it by pickling, and then try and read them back in:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "#save csv\n", "st = time.clock()\n", "import csv\n", "fn_csv = './code/io/csv_example/big_array.csv'\n", "with open(fn_csv,'wb') as csvfile:\n", " csv_writer = csv.writer(csvfile)\n", " for z_line in Z:\n", " csv_writer.writerow(z_line)\n", "print 'How long did that take? (s)', time.clock() - st\n", "# how big is this file..?\n", "import os\n", "print 'File size (MB):', os.path.getsize(fn_csv)/2**20" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "How long did that take? (s) 5.22988936046\n", "File size (MB): 80\n" ] } ], "prompt_number": 86 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Quite a large file...\n", "\n", "Let's try pickle instead..." ] }, { "cell_type": "code", "collapsed": false, "input": [ "#now pickle it instead\n", "import cPickle as pickle\n", "\n", "fn_pkl = './code/io/csv_example/big_array.pkl' # note you can have whatever extension you want here, \n", " # or none at all, but I prefer a sensible extension\n", "\n", "# pickle it\n", "st = time.clock()\n", "pickle.dump(Z,open(fn_pkl,'wb'))\n", "\n", "print 'And this time... (s)', time.clock() - st\n", "print 'File size (MB):', os.path.getsize(fn_pkl)/2**20" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "And this time... (s) 2.53754202893\n", "File size (MB): 80\n" ] } ], "prompt_number": 87 }, { "cell_type": "markdown", "metadata": {}, "source": [ "So the file sizes are the same, but the time taken is much longer by the csv writer. Now let's try reading them back in. Here's a pretty generic code for reading csv files to data arrays:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def read_file_data(filename):\n", " with open(filename,'U') as f:\n", " DataIn = csv.reader(f,delimiter=',')\n", "\n", " DataOut = []\n", " # find number of columns\n", " DataLine = DataIn.next()\n", " NCols = len(DataLine)\n", " for i in range(NCols):\n", " DataOut.append([])\n", " print NCols,len(DataOut)\n", "\n", " for row in DataIn:\n", " for i in range(NCols):\n", " try:\n", " DataOut[i].append(float(row[i]))\n", " except: # if not numeric\n", " DataOut[i].append(0)\n", " return DataOut" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 88 }, { "cell_type": "code", "collapsed": false, "input": [ "#read in csv file\n", "st = time.clock()\n", "Z = read_file_data(fn_csv)\n", "print 'Elapsed time (ms):', (time.clock() - st)*1e3" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "2000 2000\n", "Elapsed time (ms):" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 3473.91947552\n" ] } ], "prompt_number": 89 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now compare with reading in from the pickled file" ] }, { "cell_type": "code", "collapsed": false, "input": [ "st = time.clock()\n", "Z = pickle.load(open(fn_pkl,'rb'))\n", "print 'Elapsed time (ms):', (time.clock() - st)*1e3" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Elapsed time (ms): 2868.40562932\n" ] } ], "prompt_number": 90 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This might not seem like much of a speed-up, but if the file sizes get larger then this becomes a sizeable increase in performance. \n", "\n", "However, the pickle module is most useful when storing many data types, as there is no need to format the data before saving:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# pickle example for mixed data types\n", "\n", "# numpy 1d array\n", "x = np.arange(-100,100,0.01)\n", "# numpy 2d array\n", "y = np.ones((500,500))\n", "# list of mixed type\n", "z = [1,4,6,0,'abcde']\n", "# string\n", "a = 'this is a string'\n", "# tuple\n", "b = (42,'anything')\n", "\n" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 92 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's say we want to save all of this data. Instead of writing many files, it can all be bundled into one pickled file:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "fn_pkl = './code/io/csv_example/multi_out.pkl'\n", "#save\n", "pickle.dump([x,y,z,a,b],open(fn_pkl,'wb'))" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 93 }, { "cell_type": "markdown", "metadata": {}, "source": [ "And then to read it back in:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "x2,y2,z2,a2,b2 = pickle.load(open(fn_pkl,'rb'))\n", "\n", "#check the data is the same as what we put in...\n", "print 'Data arrays same?\\n', z2==z, a2==a, b2==b" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Data arrays same?\n", "True True True\n" ] } ], "prompt_number": 97 }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }