From ab66288094365ece55a7bfd0dce766c7f2f9e2f4 Mon Sep 17 00:00:00 2001 From: Brian Rose Date: Mon, 14 Jun 2021 15:43:04 -0400 Subject: [PATCH 01/15] Use pythia-datasets in pandas notebook --- core/pandas/enso_data.csv | 473 --- core/pandas/pandas_fullNotebook.ipynb | 4181 ++----------------------- environment.yml | 4 + 3 files changed, 263 insertions(+), 4395 deletions(-) delete mode 100644 core/pandas/enso_data.csv diff --git a/core/pandas/enso_data.csv b/core/pandas/enso_data.csv deleted file mode 100644 index 1ada455af..000000000 --- a/core/pandas/enso_data.csv +++ /dev/null @@ -1,473 +0,0 @@ -datetime,Nino12,Nino12anom,Nino3,Nino3anom,Nino4,Nino4anom,Nino34,Nino34anom -1982-01-01,24.29,-0.17,25.87,0.24,28.3,0.0,26.72,0.15 -1982-02-01,25.49,-0.58,26.38,0.01,28.21,0.11,26.7,-0.02 -1982-03-01,25.21,-1.31,26.98,-0.16,28.41,0.22,27.2,-0.02 -1982-04-01,24.5,-0.97,27.68,0.18,28.92,0.42,28.02,0.24 -1982-05-01,23.97,-0.23,27.79,0.71,29.49,0.7,28.54,0.69 -1982-06-01,22.89,0.07,27.46,1.03,29.76,0.92,28.75,1.1 -1982-07-01,22.47,0.87,26.44,0.82,29.38,0.58,28.1,0.88 -1982-08-01,21.75,1.1,26.15,1.16,29.04,0.36,27.93,1.11 -1982-09-01,21.8,1.44,26.52,1.67,29.16,0.47,28.11,1.39 -1982-10-01,22.94,2.12,27.11,2.19,29.38,0.72,28.64,1.95 -1982-11-01,24.59,3.0,27.62,2.64,29.23,0.6,28.81,2.16 -1982-12-01,26.13,3.34,28.39,3.25,29.15,0.66,29.21,2.64 -1983-01-01,27.42,2.96,28.92,3.29,29.0,0.7,29.36,2.79 -1983-02-01,28.09,2.02,28.92,2.55,28.79,0.69,29.13,2.41 -1983-03-01,28.68,2.16,29.1,1.96,28.76,0.57,29.03,1.81 -1983-04-01,28.56,3.09,29.12,1.62,28.85,0.35,28.91,1.13 -1983-05-01,28.19,3.99,28.97,1.89,29.08,0.29,28.89,1.04 -1983-06-01,27.44,4.62,28.15,1.72,28.88,0.04,28.24,0.59 -1983-07-01,25.95,4.35,26.62,1.0,28.65,-0.15,27.07,-0.15 -1983-08-01,23.78,3.13,25.87,0.88,28.38,-0.3,26.53,-0.29 -1983-09-01,22.24,1.88,25.24,0.39,28.23,-0.46,26.44,-0.28 -1983-10-01,21.86,1.04,24.61,-0.31,27.75,-0.91,25.87,-0.82 -1983-11-01,21.9,0.31,24.17,-0.81,27.76,-0.87,25.58,-1.07 -1983-12-01,23.01,0.22,24.44,-0.7,27.82,-0.67,25.59,-0.98 -1984-01-01,24.18,-0.28,24.82,-0.81,27.64,-0.66,25.64,-0.93 -1984-02-01,25.18,-0.89,26.22,-0.15,27.25,-0.85,26.39,-0.33 -1984-03-01,26.0,-0.52,27.12,-0.02,27.21,-0.98,26.86,-0.36 -1984-04-01,25.16,-0.31,27.34,-0.16,27.7,-0.8,27.39,-0.39 -1984-05-01,23.23,-0.97,26.46,-0.62,27.95,-0.84,27.39,-0.46 -1984-06-01,21.96,-0.86,25.38,-1.05,28.13,-0.71,26.86,-0.79 -1984-07-01,21.24,-0.36,24.96,-0.66,28.35,-0.45,26.74,-0.48 -1984-08-01,20.17,-0.48,24.5,-0.49,28.17,-0.51,26.34,-0.48 -1984-09-01,20.37,0.01,24.35,-0.5,28.61,-0.08,26.43,-0.29 -1984-10-01,20.52,-0.3,23.95,-0.97,28.28,-0.38,25.93,-0.76 -1984-11-01,21.5,-0.09,24.03,-0.95,27.99,-0.64,25.41,-1.24 -1984-12-01,22.58,-0.21,23.7,-1.44,27.44,-1.05,25.0,-1.57 -1985-01-01,23.59,-0.87,24.51,-1.12,27.71,-0.59,25.43,-1.14 -1985-02-01,24.87,-1.2,25.19,-1.18,27.55,-0.55,25.67,-1.05 -1985-03-01,25.74,-0.78,26.11,-1.03,27.38,-0.81,26.23,-0.99 -1985-04-01,24.25,-1.22,26.52,-0.98,27.72,-0.78,26.8,-0.98 -1985-05-01,22.29,-1.91,26.12,-0.96,28.06,-0.73,27.11,-0.74 -1985-06-01,21.75,-1.07,25.6,-0.83,28.08,-0.76,26.86,-0.79 -1985-07-01,20.44,-1.16,24.74,-0.88,28.28,-0.52,26.69,-0.53 -1985-08-01,19.29,-1.36,24.4,-0.59,28.32,-0.36,26.5,-0.32 -1985-09-01,19.44,-0.92,24.15,-0.7,28.33,-0.36,26.25,-0.47 -1985-10-01,19.9,-0.92,24.15,-0.77,28.28,-0.38,26.19,-0.5 -1985-11-01,20.69,-0.9,24.28,-0.7,28.52,-0.11,26.19,-0.46 -1985-12-01,22.4,-0.39,24.29,-0.85,28.53,0.04,26.11,-0.46 -1986-01-01,24.61,0.15,24.73,-0.9,28.11,-0.19,25.79,-0.78 -1986-02-01,26.06,-0.01,25.81,-0.56,27.93,-0.17,25.94,-0.78 -1986-03-01,25.91,-0.61,26.84,-0.3,27.97,-0.22,26.65,-0.57 -1986-04-01,24.58,-0.89,27.17,-0.33,28.21,-0.29,27.44,-0.34 -1986-05-01,23.38,-0.82,26.68,-0.4,28.58,-0.21,27.5,-0.35 -1986-06-01,21.98,-0.84,26.3,-0.13,28.84,0.0,27.69,0.04 -1986-07-01,21.12,-0.48,25.7,0.08,28.9,0.1,27.37,0.15 -1986-08-01,20.97,0.32,25.02,0.03,29.04,0.36,27.15,0.33 -1986-09-01,20.44,0.08,25.25,0.4,29.18,0.49,27.33,0.61 -1986-10-01,21.07,0.25,25.62,0.7,29.38,0.72,27.57,0.88 -1986-11-01,22.03,0.44,25.92,0.94,29.4,0.77,27.73,1.08 -1986-12-01,23.0,0.21,25.86,0.72,29.19,0.7,27.7,1.13 -1987-01-01,25.3,0.84,26.69,1.06,29.02,0.72,27.91,1.34 -1987-02-01,27.14,1.07,27.42,1.05,28.93,0.83,28.02,1.3 -1987-03-01,28.01,1.49,28.2,1.06,29.04,0.85,28.47,1.25 -1987-04-01,27.17,1.7,28.49,0.99,29.21,0.71,28.8,1.02 -1987-05-01,25.58,1.38,28.22,1.14,29.25,0.46,28.75,0.9 -1987-06-01,24.06,1.24,27.71,1.28,29.53,0.69,29.03,1.38 -1987-07-01,22.78,1.18,27.07,1.45,29.47,0.67,28.8,1.58 -1987-08-01,21.73,1.08,26.52,1.53,29.41,0.73,28.58,1.76 -1987-09-01,21.45,1.09,26.57,1.72,29.51,0.82,28.39,1.67 -1987-10-01,22.39,1.57,26.2,1.28,29.61,0.95,28.07,1.38 -1987-11-01,22.63,1.04,26.13,1.15,29.8,1.17,27.99,1.34 -1987-12-01,23.47,0.68,26.2,1.06,29.44,0.95,27.6,1.03 -1988-01-01,24.64,0.18,26.12,0.49,29.13,0.83,27.32,0.75 -1988-02-01,25.74,-0.33,26.55,0.18,28.69,0.59,27.22,0.5 -1988-03-01,25.78,-0.74,27.14,0.0,28.2,0.01,27.31,0.09 -1988-04-01,24.54,-0.93,26.73,-0.77,28.15,-0.35,27.32,-0.46 -1988-05-01,23.6,-0.6,25.22,-1.86,28.36,-0.43,26.48,-1.37 -1988-06-01,21.27,-1.55,24.46,-1.97,28.13,-0.71,26.11,-1.54 -1988-07-01,20.26,-1.34,23.71,-1.91,27.88,-0.92,25.57,-1.65 -1988-08-01,19.12,-1.53,23.37,-1.62,27.68,-1.0,25.24,-1.58 -1988-09-01,19.19,-1.17,23.61,-1.24,27.63,-1.06,25.43,-1.29 -1988-10-01,19.5,-1.32,23.17,-1.75,27.06,-1.6,24.62,-2.07 -1988-11-01,20.55,-1.04,23.03,-1.95,26.76,-1.87,24.27,-2.38 -1988-12-01,21.8,-0.99,23.07,-2.07,26.75,-1.74,24.33,-2.24 -1989-01-01,24.09,-0.37,24.15,-1.48,26.54,-1.76,24.53,-2.04 -1989-02-01,26.26,0.19,25.61,-0.76,26.55,-1.55,25.33,-1.39 -1989-03-01,26.66,0.14,26.02,-1.12,27.0,-1.19,25.9,-1.32 -1989-04-01,25.63,0.16,26.67,-0.83,27.54,-0.96,26.69,-1.09 -1989-05-01,23.18,-1.02,26.37,-0.71,28.14,-0.65,27.09,-0.76 -1989-06-01,22.0,-0.82,26.08,-0.35,27.94,-0.9,26.98,-0.67 -1989-07-01,21.12,-0.48,25.28,-0.34,28.2,-0.6,26.74,-0.48 -1989-08-01,20.32,-0.33,24.56,-0.43,28.14,-0.54,26.33,-0.49 -1989-09-01,19.87,-0.49,24.45,-0.4,28.25,-0.44,26.25,-0.47 -1989-10-01,20.33,-0.49,24.49,-0.43,28.39,-0.27,26.26,-0.43 -1989-11-01,21.31,-0.28,24.56,-0.42,28.23,-0.4,26.24,-0.41 -1989-12-01,22.19,-0.6,24.71,-0.43,28.52,0.03,26.38,-0.19 -1990-01-01,24.02,-0.44,25.34,-0.29,28.56,0.26,26.55,-0.02 -1990-02-01,25.88,-0.19,26.37,0.0,28.62,0.52,26.95,0.23 -1990-03-01,26.16,-0.36,27.03,-0.11,28.78,0.59,27.46,0.24 -1990-04-01,25.22,-0.25,27.67,0.17,28.93,0.43,28.02,0.24 -1990-05-01,24.05,-0.15,27.35,0.27,28.96,0.17,28.06,0.21 -1990-06-01,22.68,-0.14,26.45,0.02,28.94,0.1,27.58,-0.07 -1990-07-01,21.0,-0.6,25.45,-0.17,28.98,0.18,27.25,0.03 -1990-08-01,20.25,-0.4,25.06,0.07,29.17,0.49,27.05,0.23 -1990-09-01,20.13,-0.23,24.85,0.0,29.04,0.35,26.75,0.03 -1990-10-01,20.28,-0.54,24.9,-0.02,29.23,0.57,26.98,0.29 -1990-11-01,20.84,-0.75,24.82,-0.16,29.06,0.43,26.72,0.07 -1990-12-01,22.45,-0.34,25.08,-0.06,29.14,0.65,26.91,0.34 -1991-01-01,23.86,-0.6,25.65,0.02,29.0,0.7,27.01,0.44 -1991-02-01,25.97,-0.1,26.27,-0.1,28.73,0.63,26.93,0.21 -1991-03-01,26.51,-0.01,26.99,-0.15,28.64,0.45,27.25,0.03 -1991-04-01,24.99,-0.48,27.32,-0.18,29.13,0.63,27.98,0.2 -1991-05-01,24.37,0.17,27.58,0.5,29.42,0.63,28.35,0.5 -1991-06-01,23.05,0.23,27.34,0.91,29.35,0.51,28.36,0.71 -1991-07-01,22.05,0.45,26.57,0.95,29.26,0.46,27.92,0.7 -1991-08-01,21.08,0.43,25.47,0.48,29.25,0.57,27.44,0.62 -1991-09-01,20.75,0.39,25.05,0.2,29.19,0.5,27.07,0.35 -1991-10-01,21.13,0.31,25.6,0.68,29.44,0.78,27.63,0.94 -1991-11-01,22.18,0.59,25.98,1.0,29.45,0.82,27.86,1.21 -1991-12-01,23.43,0.64,26.52,1.38,29.45,0.96,28.37,1.8 -1992-01-01,24.83,0.37,27.0,1.37,29.06,0.76,28.41,1.84 -1992-02-01,26.68,0.61,27.67,1.3,29.02,0.92,28.63,1.91 -1992-03-01,27.76,1.24,28.33,1.19,29.08,0.89,28.83,1.61 -1992-04-01,27.68,2.21,28.72,1.22,29.42,0.92,29.14,1.36 -1992-05-01,26.31,2.11,28.43,1.35,29.46,0.67,28.99,1.14 -1992-06-01,23.82,1.0,26.66,0.23,29.31,0.47,28.02,0.37 -1992-07-01,21.95,0.35,25.53,-0.09,29.35,0.55,27.53,0.31 -1992-08-01,20.55,-0.1,24.7,-0.29,28.9,0.22,26.64,-0.18 -1992-09-01,20.06,-0.3,24.52,-0.33,28.79,0.1,26.48,-0.24 -1992-10-01,20.82,0.0,24.62,-0.3,28.69,0.03,26.34,-0.35 -1992-11-01,21.49,-0.1,24.79,-0.19,28.7,0.07,26.51,-0.14 -1992-12-01,22.48,-0.31,25.01,-0.13,28.76,0.27,26.73,0.16 -1993-01-01,24.43,-0.03,25.56,-0.07,28.6,0.3,26.69,0.12 -1993-02-01,26.49,0.42,26.61,0.24,28.41,0.31,26.97,0.25 -1993-03-01,27.17,0.65,27.54,0.4,28.6,0.41,27.66,0.44 -1993-04-01,26.44,0.97,28.45,0.95,28.93,0.43,28.59,0.81 -1993-05-01,25.15,0.95,28.16,1.08,29.13,0.34,28.82,0.97 -1993-06-01,23.76,0.94,27.11,0.68,29.17,0.33,28.28,0.63 -1993-07-01,22.06,0.46,25.77,0.15,29.2,0.4,27.55,0.33 -1993-08-01,21.05,0.4,24.93,-0.06,28.94,0.26,26.84,0.02 -1993-09-01,20.83,0.47,24.97,0.12,29.07,0.38,26.92,0.2 -1993-10-01,20.99,0.17,25.21,0.29,28.9,0.24,26.93,0.24 -1993-11-01,21.64,0.05,25.17,0.19,28.97,0.34,26.91,0.26 -1993-12-01,22.75,-0.04,25.32,0.18,28.9,0.41,26.76,0.19 -1994-01-01,24.32,-0.14,25.71,0.08,28.47,0.17,26.6,0.03 -1994-02-01,25.79,-0.28,26.07,-0.3,28.07,-0.03,26.59,-0.13 -1994-03-01,25.43,-1.09,26.89,-0.25,28.26,0.07,27.27,0.05 -1994-04-01,24.32,-1.15,27.06,-0.44,28.62,0.12,27.9,0.12 -1994-05-01,23.22,-0.98,26.97,-0.11,29.0,0.21,28.04,0.19 -1994-06-01,22.43,-0.39,26.5,0.07,29.18,0.34,27.99,0.34 -1994-07-01,21.21,-0.39,25.19,-0.43,29.4,0.6,27.35,0.13 -1994-08-01,19.7,-0.95,24.71,-0.28,29.46,0.78,27.35,0.53 -1994-09-01,20.16,-0.2,24.81,-0.04,29.23,0.54,27.0,0.28 -1994-10-01,21.53,0.71,25.53,0.61,29.45,0.79,27.49,0.8 -1994-11-01,22.41,0.82,25.87,0.89,29.63,1.0,27.87,1.22 -1994-12-01,23.61,0.82,26.07,0.93,29.5,1.01,27.87,1.3 -1995-01-01,25.33,0.87,26.34,0.71,29.2,0.9,27.55,0.98 -1995-02-01,26.43,0.36,26.87,0.5,29.01,0.91,27.45,0.73 -1995-03-01,26.12,-0.4,27.08,-0.06,28.96,0.77,27.63,0.41 -1995-04-01,24.47,-1.0,27.1,-0.4,28.89,0.39,27.93,0.15 -1995-05-01,23.1,-1.1,26.4,-0.68,29.15,0.36,27.73,-0.12 -1995-06-01,22.45,-0.37,26.2,-0.23,29.01,0.17,27.59,-0.06 -1995-07-01,21.23,-0.37,25.42,-0.2,28.78,-0.02,27.01,-0.21 -1995-08-01,20.01,-0.64,24.33,-0.66,28.43,-0.25,26.33,-0.49 -1995-09-01,20.17,-0.19,24.02,-0.83,28.25,-0.44,25.96,-0.76 -1995-10-01,20.15,-0.67,24.01,-0.91,28.07,-0.59,25.67,-1.02 -1995-11-01,21.2,-0.39,24.03,-0.95,27.97,-0.66,25.66,-0.99 -1995-12-01,22.02,-0.77,24.19,-0.95,28.07,-0.42,25.57,-1.0 -1996-01-01,23.84,-0.62,24.96,-0.67,27.92,-0.38,25.74,-0.83 -1996-02-01,25.71,-0.36,25.72,-0.65,27.57,-0.53,25.85,-0.87 -1996-03-01,26.09,-0.43,26.71,-0.43,27.71,-0.48,26.62,-0.6 -1996-04-01,23.85,-1.62,26.72,-0.78,28.07,-0.43,27.36,-0.42 -1996-05-01,22.89,-1.31,26.33,-0.75,28.43,-0.36,27.37,-0.48 -1996-06-01,21.56,-1.26,25.89,-0.54,28.55,-0.29,27.32,-0.33 -1996-07-01,20.02,-1.58,25.35,-0.27,28.5,-0.3,27.09,-0.13 -1996-08-01,19.53,-1.12,24.6,-0.39,28.54,-0.14,26.56,-0.26 -1996-09-01,19.24,-1.12,24.37,-0.48,28.43,-0.26,26.35,-0.37 -1996-10-01,19.95,-0.87,24.37,-0.55,28.42,-0.24,26.24,-0.45 -1996-11-01,20.26,-1.33,24.38,-0.6,28.33,-0.3,26.19,-0.46 -1996-12-01,21.61,-1.18,24.2,-0.94,28.44,-0.05,26.02,-0.55 -1997-01-01,23.67,-0.79,24.7,-0.93,28.41,0.11,25.96,-0.61 -1997-02-01,25.74,-0.33,25.75,-0.62,28.33,0.23,26.36,-0.36 -1997-03-01,26.95,0.43,26.98,-0.16,28.52,0.33,27.03,-0.19 -1997-04-01,26.64,1.17,27.59,0.09,29.32,0.82,28.03,0.25 -1997-05-01,26.71,2.51,28.06,0.98,29.45,0.66,28.6,0.75 -1997-06-01,26.27,3.45,28.14,1.71,29.4,0.56,28.94,1.29 -1997-07-01,25.59,3.99,28.01,2.39,29.5,0.7,28.92,1.7 -1997-08-01,24.8,4.15,27.84,2.85,29.26,0.58,28.84,2.02 -1997-09-01,24.4,4.04,27.84,2.99,29.32,0.63,28.93,2.21 -1997-10-01,24.58,3.76,28.17,3.25,29.32,0.66,29.23,2.54 -1997-11-01,25.63,4.04,28.55,3.57,29.49,0.86,29.32,2.67 -1997-12-01,26.92,4.13,28.76,3.62,29.32,0.83,29.26,2.69 -1998-01-01,28.22,3.76,28.94,3.31,29.01,0.71,29.1,2.53 -1998-02-01,28.98,2.91,28.93,2.56,28.87,0.77,28.86,2.14 -1998-03-01,29.15,2.63,29.14,2.0,28.65,0.46,28.67,1.45 -1998-04-01,28.61,3.14,29.09,1.59,28.53,0.03,28.56,0.78 -1998-05-01,27.69,3.49,28.17,1.09,28.71,-0.08,28.47,0.62 -1998-06-01,25.18,2.36,26.0,-0.43,28.61,-0.23,26.72,-0.93 -1998-07-01,23.43,1.83,25.24,-0.38,28.07,-0.73,25.94,-1.28 -1998-08-01,21.77,1.12,24.63,-0.36,27.77,-0.91,25.49,-1.33 -1998-09-01,20.87,0.51,24.19,-0.66,27.88,-0.81,25.61,-1.11 -1998-10-01,21.16,0.34,24.06,-0.86,27.33,-1.33,25.34,-1.35 -1998-11-01,21.43,-0.16,24.11,-0.87,27.23,-1.4,25.18,-1.47 -1998-12-01,22.56,-0.23,23.86,-1.28,27.11,-1.38,24.79,-1.78 -1999-01-01,23.73,-0.73,24.41,-1.22,26.59,-1.71,24.9,-1.67 -1999-02-01,25.64,-0.43,25.57,-0.8,26.52,-1.58,25.41,-1.31 -1999-03-01,26.62,0.1,26.67,-0.47,26.9,-1.29,26.25,-0.97 -1999-04-01,24.3,-1.17,26.66,-0.84,27.35,-1.15,26.84,-0.94 -1999-05-01,23.46,-0.74,26.44,-0.64,27.87,-0.92,26.97,-0.88 -1999-06-01,21.83,-0.99,25.59,-0.84,28.01,-0.83,26.6,-1.05 -1999-07-01,20.44,-1.16,24.85,-0.77,27.92,-0.88,26.35,-0.87 -1999-08-01,19.75,-0.9,24.02,-0.97,27.73,-0.95,25.59,-1.23 -1999-09-01,19.23,-1.13,23.72,-1.13,27.82,-0.87,25.71,-1.01 -1999-10-01,20.05,-0.77,23.75,-1.17,27.85,-0.81,25.64,-1.05 -1999-11-01,20.51,-1.08,23.46,-1.52,27.56,-1.07,25.12,-1.53 -1999-12-01,21.72,-1.07,23.54,-1.6,27.23,-1.26,24.9,-1.67 -2000-01-01,23.86,-0.6,23.88,-1.75,26.96,-1.34,24.65,-1.92 -2000-02-01,25.71,-0.36,25.31,-1.06,26.66,-1.44,25.19,-1.53 -2000-03-01,26.19,-0.33,26.61,-0.53,26.76,-1.43,26.08,-1.14 -2000-04-01,25.84,0.37,27.46,-0.04,27.37,-1.13,27.01,-0.77 -2000-05-01,24.1,-0.1,26.8,-0.28,27.81,-0.98,27.12,-0.73 -2000-06-01,22.25,-0.57,25.84,-0.59,28.11,-0.73,27.03,-0.62 -2000-07-01,20.59,-1.01,25.13,-0.49,28.2,-0.6,26.72,-0.5 -2000-08-01,20.1,-0.55,24.47,-0.52,28.32,-0.36,26.45,-0.37 -2000-09-01,19.94,-0.42,24.35,-0.5,28.44,-0.25,26.21,-0.51 -2000-10-01,20.37,-0.45,24.41,-0.51,28.17,-0.49,25.96,-0.73 -2000-11-01,20.6,-0.99,24.17,-0.81,28.09,-0.54,25.78,-0.87 -2000-12-01,22.22,-0.57,24.43,-0.71,27.6,-0.89,25.59,-0.98 -2001-01-01,23.88,-0.58,24.99,-0.64,27.5,-0.8,25.74,-0.83 -2001-02-01,25.91,-0.16,26.06,-0.31,27.27,-0.83,26.11,-0.61 -2001-03-01,27.44,0.92,27.23,0.09,27.62,-0.57,26.84,-0.38 -2001-04-01,26.69,1.22,27.52,0.02,28.19,-0.31,27.52,-0.26 -2001-05-01,23.77,-0.43,26.89,-0.19,28.64,-0.15,27.6,-0.25 -2001-06-01,21.74,-1.08,26.35,-0.08,28.83,-0.01,27.68,0.03 -2001-07-01,20.88,-0.72,25.43,-0.19,29.06,0.26,27.32,0.1 -2001-08-01,19.9,-0.75,24.72,-0.27,28.96,0.28,26.87,0.05 -2001-09-01,19.39,-0.97,24.27,-0.58,29.14,0.45,26.55,-0.17 -2001-10-01,19.52,-1.3,24.45,-0.47,29.01,0.35,26.59,-0.1 -2001-11-01,20.49,-1.1,24.35,-0.63,28.96,0.33,26.45,-0.2 -2001-12-01,21.96,-0.83,24.6,-0.54,28.6,0.11,26.17,-0.4 -2002-01-01,23.64,-0.82,25.09,-0.54,28.81,0.51,26.5,-0.07 -2002-02-01,26.06,-0.01,26.21,-0.16,28.76,0.66,26.95,0.23 -2002-03-01,27.53,1.01,27.22,0.08,28.68,0.49,27.32,0.1 -2002-04-01,26.53,1.06,27.56,0.06,29.09,0.59,27.94,0.16 -2002-05-01,24.8,0.6,27.24,0.16,29.45,0.66,28.15,0.3 -2002-06-01,22.67,-0.15,27.06,0.63,29.63,0.79,28.43,0.78 -2002-07-01,21.01,-0.59,26.03,0.41,29.49,0.69,27.98,0.76 -2002-08-01,19.94,-0.71,25.47,0.48,29.4,0.72,27.79,0.97 -2002-09-01,19.89,-0.47,25.54,0.69,29.44,0.75,27.83,1.11 -2002-10-01,21.16,0.34,25.85,0.93,29.56,0.9,28.05,1.36 -2002-11-01,22.25,0.66,26.37,1.39,29.83,1.2,28.27,1.62 -2002-12-01,23.44,0.65,26.48,1.34,29.49,1.0,28.09,1.52 -2003-01-01,24.38,-0.08,26.38,0.75,29.25,0.95,27.76,1.19 -2003-02-01,25.81,-0.26,26.7,0.33,29.03,0.93,27.49,0.77 -2003-03-01,25.97,-0.55,27.28,0.14,29.03,0.84,27.81,0.59 -2003-04-01,24.44,-1.03,27.15,-0.35,28.96,0.46,27.81,0.03 -2003-05-01,22.49,-1.71,26.14,-0.94,28.92,0.13,27.37,-0.48 -2003-06-01,21.58,-1.24,25.83,-0.6,29.09,0.25,27.48,-0.17 -2003-07-01,20.75,-0.85,25.75,0.13,29.11,0.31,27.43,0.21 -2003-08-01,20.14,-0.51,25.04,0.05,29.05,0.37,26.85,0.03 -2003-09-01,20.0,-0.36,24.97,0.12,29.02,0.33,26.96,0.24 -2003-10-01,20.99,0.17,25.33,0.41,29.22,0.56,27.19,0.5 -2003-11-01,21.92,0.33,25.4,0.42,29.31,0.68,27.05,0.4 -2003-12-01,22.99,0.2,25.56,0.42,29.02,0.53,26.89,0.32 -2004-01-01,24.6,0.14,25.92,0.29,28.83,0.53,26.74,0.17 -2004-02-01,25.81,-0.26,26.46,0.09,28.59,0.49,26.86,0.14 -2004-03-01,25.94,-0.58,27.16,0.02,28.43,0.24,27.1,-0.12 -2004-04-01,25.32,-0.15,27.37,-0.13,28.75,0.25,27.84,0.06 -2004-05-01,23.05,-1.15,26.72,-0.36,29.16,0.37,28.06,0.21 -2004-06-01,21.6,-1.22,26.27,-0.16,29.17,0.33,27.76,0.11 -2004-07-01,20.71,-0.89,25.41,-0.21,29.39,0.59,27.69,0.47 -2004-08-01,19.62,-1.03,25.05,0.06,29.31,0.63,27.54,0.72 -2004-09-01,20.07,-0.29,25.17,0.32,29.6,0.91,27.47,0.75 -2004-10-01,20.92,0.1,25.32,0.4,29.55,0.89,27.38,0.69 -2004-11-01,21.96,0.37,25.46,0.48,29.57,0.94,27.31,0.66 -2004-12-01,22.94,0.15,25.77,0.63,29.4,0.91,27.31,0.74 -2005-01-01,24.47,0.01,25.89,0.26,29.21,0.91,27.1,0.53 -2005-02-01,25.49,-0.58,26.2,-0.17,28.83,0.73,26.96,0.24 -2005-03-01,25.6,-0.92,27.01,-0.13,28.91,0.72,27.55,0.33 -2005-04-01,24.9,-0.57,27.77,0.27,28.96,0.46,28.07,0.29 -2005-05-01,24.4,0.2,27.48,0.4,29.18,0.39,28.2,0.35 -2005-06-01,22.47,-0.35,26.81,0.38,29.18,0.34,28.05,0.4 -2005-07-01,21.18,-0.42,25.93,0.31,29.05,0.25,27.47,0.25 -2005-08-01,20.61,-0.04,25.19,0.2,28.86,0.18,26.88,0.06 -2005-09-01,19.71,-0.65,24.57,-0.28,28.84,0.15,26.63,-0.09 -2005-10-01,19.72,-1.1,24.69,-0.23,28.89,0.23,26.75,0.06 -2005-11-01,20.62,-0.97,24.28,-0.7,28.67,0.04,26.34,-0.31 -2005-12-01,22.29,-0.5,24.28,-0.86,28.35,-0.14,25.89,-0.68 -2006-01-01,24.33,-0.13,25.0,-0.63,27.68,-0.62,25.64,-0.93 -2006-02-01,26.46,0.39,26.08,-0.29,27.39,-0.71,26.08,-0.64 -2006-03-01,26.77,0.25,26.54,-0.6,27.79,-0.4,26.57,-0.65 -2006-04-01,24.15,-1.32,27.25,-0.25,28.38,-0.12,27.59,-0.19 -2006-05-01,23.86,-0.34,27.04,-0.04,28.91,0.12,27.91,0.06 -2006-06-01,22.77,-0.05,26.44,0.01,29.15,0.31,27.85,0.2 -2006-07-01,22.19,0.59,25.8,0.18,29.07,0.27,27.35,0.13 -2006-08-01,21.59,0.94,25.45,0.46,29.22,0.54,27.22,0.4 -2006-09-01,21.43,1.07,25.74,0.89,29.4,0.71,27.34,0.62 -2006-10-01,22.22,1.4,25.96,1.04,29.44,0.78,27.47,0.78 -2006-11-01,22.69,1.1,26.07,1.09,29.63,1.0,27.73,1.08 -2006-12-01,23.45,0.66,26.36,1.22,29.47,0.98,27.76,1.19 -2007-01-01,24.99,0.53,26.5,0.87,28.93,0.63,27.26,0.69 -2007-02-01,26.24,0.17,26.45,0.08,28.62,0.52,26.81,0.09 -2007-03-01,25.74,-0.78,26.79,-0.35,28.57,0.38,27.18,-0.04 -2007-04-01,24.3,-1.17,27.13,-0.37,28.7,0.2,27.78,0.0 -2007-05-01,22.73,-1.47,26.35,-0.73,28.86,0.07,27.57,-0.28 -2007-06-01,21.59,-1.23,25.83,-0.6,28.98,0.14,27.55,-0.1 -2007-07-01,20.27,-1.33,24.79,-0.83,28.81,0.01,26.79,-0.43 -2007-08-01,19.16,-1.49,23.86,-1.13,28.58,-0.1,26.2,-0.62 -2007-09-01,18.57,-1.79,23.52,-1.33,28.12,-0.57,25.77,-0.95 -2007-10-01,18.8,-2.02,23.36,-1.56,27.86,-0.8,25.22,-1.47 -2007-11-01,19.49,-2.1,23.17,-1.81,27.42,-1.21,25.06,-1.59 -2007-12-01,21.02,-1.77,23.59,-1.55,27.3,-1.19,24.97,-1.6 -2008-01-01,23.86,-0.6,24.13,-1.5,26.62,-1.68,24.71,-1.86 -2008-02-01,26.32,0.25,25.05,-1.32,26.43,-1.67,24.83,-1.89 -2008-03-01,27.3,0.78,26.56,-0.58,26.84,-1.35,26.07,-1.15 -2008-04-01,25.89,0.42,27.18,-0.32,27.44,-1.06,26.83,-0.95 -2008-05-01,24.41,0.21,27.08,0.0,27.9,-0.89,27.18,-0.67 -2008-06-01,23.55,0.73,26.53,0.1,28.08,-0.76,27.17,-0.48 -2008-07-01,22.63,1.03,26.12,0.5,28.25,-0.55,27.19,-0.03 -2008-08-01,21.79,1.14,25.63,0.64,28.18,-0.5,26.85,0.03 -2008-09-01,21.19,0.83,25.09,0.24,28.14,-0.55,26.44,-0.28 -2008-10-01,20.75,-0.07,24.79,-0.13,28.29,-0.37,26.33,-0.36 -2008-11-01,21.44,-0.15,24.75,-0.23,28.08,-0.55,26.3,-0.35 -2008-12-01,22.43,-0.36,24.6,-0.54,27.72,-0.77,25.74,-0.83 -2009-01-01,24.42,-0.1,25.03,-0.6,27.42,-0.88,25.54,-1.03 -2009-02-01,26.03,-0.11,25.85,-0.52,27.37,-0.73,26.04,-0.68 -2009-03-01,26.38,-0.26,26.44,-0.7,27.79,-0.4,26.67,-0.55 -2009-04-01,25.98,0.37,27.39,-0.11,28.37,-0.13,27.5,-0.27 -2009-05-01,24.83,0.56,27.4,0.32,28.99,0.2,28.03,0.18 -2009-06-01,23.73,0.85,27.12,0.69,29.2,0.36,28.11,0.47 -2009-07-01,22.63,1.02,26.56,0.94,29.21,0.4,27.94,0.72 -2009-08-01,21.64,1.0,25.94,0.95,29.21,0.53,27.53,0.71 -2009-09-01,20.82,0.47,25.66,0.8,29.28,0.58,27.47,0.75 -2009-10-01,20.96,0.17,25.73,0.81,29.65,0.99,27.63,0.94 -2009-11-01,22.11,0.51,26.23,1.26,29.88,1.25,28.19,1.54 -2009-12-01,23.16,0.35,26.67,1.53,29.67,1.18,28.3,1.72 -2010-01-01,24.82,0.3,26.63,1.0,29.51,1.21,28.07,1.5 -2010-02-01,26.08,-0.06,27.12,0.75,29.1,1.0,27.94,1.22 -2010-03-01,26.24,-0.4,27.73,0.6,29.21,1.02,28.29,1.08 -2010-04-01,26.05,0.45,28.05,0.55,29.25,0.74,28.36,0.59 -2010-05-01,24.28,0.0,26.97,-0.11,29.03,0.24,27.68,-0.17 -2010-06-01,22.6,-0.27,25.75,-0.68,28.64,-0.21,27.0,-0.65 -2010-07-01,20.08,-1.54,24.53,-1.09,28.09,-0.71,26.09,-1.13 -2010-08-01,19.27,-1.37,23.87,-1.12,27.47,-1.2,25.5,-1.32 -2010-09-01,18.9,-1.44,23.59,-1.26,27.13,-1.56,25.07,-1.65 -2010-10-01,19.06,-1.73,23.25,-1.66,27.06,-1.6,25.01,-1.68 -2010-11-01,20.03,-1.56,23.4,-1.58,27.07,-1.57,25.07,-1.58 -2010-12-01,21.48,-1.34,23.5,-1.64,26.89,-1.6,24.95,-1.62 -2011-01-01,24.08,-0.44,24.31,-1.32,26.72,-1.58,24.93,-1.64 -2011-02-01,26.22,0.08,25.55,-0.82,26.95,-1.15,25.46,-1.27 -2011-03-01,26.21,-0.43,26.39,-0.75,27.42,-0.77,26.23,-0.98 -2011-04-01,25.76,0.16,27.18,-0.32,27.86,-0.64,27.02,-0.76 -2011-05-01,24.89,0.62,26.94,-0.14,28.28,-0.51,27.42,-0.43 -2011-06-01,23.72,0.85,26.54,0.1,28.47,-0.37,27.46,-0.18 -2011-07-01,22.07,0.45,25.61,-0.01,28.47,-0.33,26.96,-0.26 -2011-08-01,20.64,0.0,24.58,-0.42,28.32,-0.36,26.19,-0.64 -2011-09-01,19.75,-0.59,24.22,-0.63,28.05,-0.64,25.98,-0.74 -2011-10-01,20.19,-0.6,23.97,-0.95,27.94,-0.72,25.72,-0.97 -2011-11-01,20.79,-0.8,23.89,-1.09,27.87,-0.77,25.6,-1.05 -2011-12-01,21.85,-0.96,24.2,-0.94,27.39,-1.1,25.53,-1.04 -2012-01-01,23.88,-0.64,24.9,-0.73,27.09,-1.21,25.49,-1.08 -2012-02-01,26.3,0.16,26.19,-0.18,27.2,-0.9,26.03,-0.69 -2012-03-01,26.91,0.27,26.92,-0.21,27.53,-0.66,26.63,-0.58 -2012-04-01,26.9,1.3,27.58,0.08,28.16,-0.34,27.38,-0.39 -2012-05-01,25.48,1.2,27.23,0.15,28.53,-0.26,27.8,-0.05 -2012-06-01,24.47,1.59,27.09,0.66,28.73,-0.11,27.95,0.31 -2012-07-01,22.61,0.99,26.54,0.92,28.86,0.06,27.75,0.53 -2012-08-01,20.99,0.35,25.72,0.73,29.1,0.42,27.55,0.73 -2012-09-01,20.83,0.49,25.28,0.43,29.12,0.43,27.24,0.51 -2012-10-01,20.68,-0.11,24.93,0.01,29.16,0.5,26.98,0.29 -2012-11-01,21.21,-0.38,25.11,0.14,29.17,0.54,27.01,0.36 -2012-12-01,22.13,-0.68,24.91,-0.23,28.71,0.23,26.46,-0.11 -2013-01-01,24.0,-0.52,25.06,-0.57,28.28,-0.02,26.16,-0.41 -2013-02-01,25.74,-0.41,25.9,-0.46,28.06,-0.04,26.32,-0.4 -2013-03-01,26.71,0.07,27.21,0.07,27.95,-0.24,27.0,-0.22 -2013-04-01,24.74,-0.86,27.35,-0.15,28.47,-0.03,27.68,-0.1 -2013-05-01,22.89,-1.38,26.39,-0.69,28.71,-0.08,27.57,-0.27 -2013-06-01,21.48,-1.4,25.8,-0.64,28.76,-0.08,27.43,-0.21 -2013-07-01,20.29,-1.33,24.97,-0.66,28.76,-0.04,26.91,-0.31 -2013-08-01,19.66,-0.98,24.44,-0.55,28.71,0.03,26.54,-0.28 -2013-09-01,19.78,-0.57,24.72,-0.13,28.7,0.01,26.65,-0.07 -2013-10-01,20.16,-0.63,24.7,-0.21,28.7,0.04,26.36,-0.33 -2013-11-01,21.06,-0.54,24.81,-0.17,28.91,0.27,26.65,0.01 -2013-12-01,22.61,-0.2,25.1,-0.04,28.64,0.15,26.53,-0.04 -2014-01-01,24.79,0.27,25.26,-0.37,28.14,-0.17,26.06,-0.51 -2014-02-01,25.4,-0.75,25.56,-0.81,28.37,0.27,26.18,-0.55 -2014-03-01,25.86,-0.78,26.9,-0.24,28.71,0.52,26.99,-0.22 -2014-04-01,25.23,-0.37,27.73,0.23,29.13,0.63,28.01,0.24 -2014-05-01,25.57,1.3,27.69,0.61,29.56,0.77,28.31,0.46 -2014-06-01,24.51,1.64,27.32,0.89,29.43,0.59,28.11,0.46 -2014-07-01,22.98,1.36,26.27,0.65,29.09,0.29,27.4,0.18 -2014-08-01,21.91,1.27,25.51,0.52,29.14,0.46,27.02,0.2 -2014-09-01,21.3,0.96,25.31,0.45,29.34,0.65,27.17,0.45 -2014-10-01,21.54,0.75,25.58,0.66,29.31,0.64,27.17,0.49 -2014-11-01,22.33,0.74,25.88,0.91,29.52,0.88,27.5,0.85 -2014-12-01,22.9,0.08,25.94,0.8,29.4,0.91,27.35,0.78 -2015-01-01,24.13,-0.39,25.99,0.36,29.16,0.86,27.1,0.53 -2015-02-01,25.59,-0.55,26.55,0.18,29.12,1.02,27.29,0.56 -2015-03-01,26.69,0.06,27.29,0.15,29.32,1.13,27.79,0.58 -2015-04-01,26.95,1.35,28.17,0.67,29.73,1.23,28.56,0.78 -2015-05-01,26.71,2.43,28.28,1.19,29.88,1.09,28.88,1.03 -2015-06-01,25.42,2.54,28.1,1.66,29.93,1.09,28.96,1.32 -2015-07-01,24.48,2.87,27.79,2.17,29.8,1.0,28.82,1.6 -2015-08-01,22.88,2.24,27.33,2.34,29.66,0.98,28.89,2.07 -2015-09-01,22.91,2.57,27.48,2.63,29.73,1.04,29.0,2.28 -2015-10-01,23.31,2.52,27.58,2.66,29.79,1.12,29.15,2.46 -2015-11-01,23.83,2.24,27.91,2.93,30.3,1.67,29.6,2.95 -2015-12-01,25.01,2.19,27.99,2.85,30.11,1.63,29.39,2.82 -2016-01-01,25.93,1.41,28.21,2.58,29.65,1.35,29.17,2.6 -2016-02-01,26.81,0.67,28.36,1.99,29.55,1.45,29.12,2.4 -2016-03-01,27.57,0.93,28.7,1.57,29.53,1.34,28.9,1.68 -2016-04-01,25.83,0.23,28.34,0.84,29.39,0.89,28.87,1.09 -2016-05-01,24.55,0.27,27.11,0.03,29.39,0.6,28.15,0.3 -2016-06-01,23.17,0.29,26.31,-0.12,29.36,0.52,27.53,-0.12 -2016-07-01,21.79,0.17,25.14,-0.48,29.06,0.26,26.73,-0.49 -2016-08-01,21.03,0.39,24.53,-0.46,28.68,-0.0,26.28,-0.54 -2016-09-01,20.87,0.53,24.67,-0.18,28.48,-0.21,26.11,-0.61 -2016-10-01,21.18,0.39,24.47,-0.45,28.26,-0.4,25.96,-0.73 -2016-11-01,21.68,0.09,24.58,-0.4,28.27,-0.37,26.1,-0.55 -2016-12-01,23.35,0.53,24.78,-0.36,28.35,-0.14,26.16,-0.41 -2017-01-01,25.75,1.23,25.61,-0.02,28.18,-0.12,26.25,-0.32 -2017-02-01,27.76,1.62,27.0,0.63,28.03,-0.07,26.87,0.14 -2017-03-01,28.52,1.89,27.7,0.57,28.13,-0.06,27.34,0.13 -2017-04-01,26.53,0.93,28.09,0.59,28.65,0.15,28.1,0.32 -2017-05-01,25.06,0.78,27.6,0.51,29.08,0.29,28.3,0.46 -2017-06-01,22.98,0.1,26.73,0.3,29.39,0.55,28.19,0.55 -2017-07-01,21.54,-0.07,25.85,0.23,29.21,0.4,27.61,0.39 -2017-08-01,20.19,-0.45,24.82,-0.17,28.87,0.19,26.67,-0.15 -2017-09-01,19.67,-0.67,24.17,-0.68,28.69,0.0,26.29,-0.43 -2017-10-01,19.45,-1.34,24.28,-0.64,28.55,-0.11,26.23,-0.46 -2017-11-01,20.44,-1.15,23.92,-1.05,28.46,-0.18,25.79,-0.86 -2017-12-01,21.44,-1.38,24.05,-1.09,28.24,-0.25,25.8,-0.77 -2018-01-01,23.71,-0.81,24.48,-1.14,28.03,-0.27,25.82,-0.75 -2018-02-01,25.57,-0.57,25.36,-1.01,27.86,-0.24,25.83,-0.9 -2018-03-01,25.83,-0.8,26.37,-0.76,28.14,-0.05,26.48,-0.73 -2018-04-01,24.58,-1.02,27.12,-0.38,28.63,0.12,27.42,-0.36 -2018-05-01,23.73,-0.54,26.94,-0.15,29.01,0.22,27.72,-0.13 -2018-06-01,22.19,-0.69,26.72,0.29,29.16,0.32,27.85,0.2 -2018-07-01,21.43,-0.19,26.05,0.43,29.1,0.3,27.52,0.3 -2018-08-01,20.66,0.02,25.14,0.15,29.19,0.51,27.11,0.29 -2018-09-01,20.31,-0.03,25.2,0.35,29.17,0.48,27.1,0.38 -2018-10-01,21.23,0.43,25.78,0.86,29.61,0.95,27.55,0.86 -2018-11-01,22.27,0.68,26.02,1.05,29.59,0.95,27.64,0.99 -2018-12-01,23.6,0.78,26.12,0.98,29.52,1.03,27.53,0.96 -2019-01-01,25.1,0.57,26.17,0.55,29.0,0.65,27.08,0.52 -2019-02-01,26.45,0.24,26.91,0.55,29.06,0.86,27.41,0.68 -2019-03-01,26.8,0.07,27.89,0.71,29.1,0.77,28.22,0.95 -2019-04-01,25.68,-0.01,28.17,0.56,29.24,0.56,28.6,0.71 -2019-05-01,24.38,-0.08,27.69,0.51,29.58,0.63,28.57,0.62 -2019-06-01,22.62,-0.38,26.81,0.27,29.62,0.6,28.24,0.47 -2019-07-01,21.34,-0.33,25.68,-0.07,29.73,0.77,27.63,0.3 -2019-08-01,20.2,-0.46,24.89,-0.15,29.5,0.68,26.97,0.1 -2019-09-01,19.5,-0.83,24.61,-0.23,29.33,0.55,26.7,-0.03 -2019-10-01,20.02,-0.71,25.12,0.17,29.64,0.88,27.31,0.59 -2019-11-01,21.32,-0.22,25.46,0.41,29.47,0.7,27.26,0.51 -2019-12-01,23.16,0.4,25.47,0.26,29.5,0.91,27.07,0.43 -2020-01-01,24.55,0.02,25.81,0.2,29.28,0.93,27.09,0.53 -2020-02-01,26.56,0.35,26.61,0.24,29.17,0.98,27.14,0.41 -2020-03-01,27.11,0.38,27.43,0.24,29.22,0.89,27.82,0.55 -2020-04-01,26.0,0.32,28.01,0.4,29.29,0.61,28.32,0.44 -2020-05-01,24.24,-0.22,26.82,-0.36,28.94,-0.01,27.59,-0.36 -2020-06-01,22.13,-0.87,25.75,-0.79,29.07,0.05,27.3,-0.47 -2020-07-01,20.44,-1.23,25.08,-0.66,28.83,-0.13,26.89,-0.44 -2020-08-01,19.69,-0.97,24.42,-0.62,28.47,-0.35,26.18,-0.69 -2020-09-01,19.48,-0.85,23.58,-1.26,28.29,-0.49,25.77,-0.96 -2020-10-01,19.67,-1.07,23.61,-1.34,27.89,-0.87,25.3,-1.42 -2020-11-01,20.94,-0.61,23.82,-1.23,27.91,-0.86,25.34,-1.42 -2020-12-01,22.16,-0.6,24.38,-0.83,27.65,-0.95,25.53,-1.12 -2021-01-01,23.89,-0.64,25.06,-0.55,27.1,-1.25,25.58,-0.99 -2021-02-01,25.55,-0.66,25.8,-0.57,27.2,-1.0,25.81,-0.92 -2021-03-01,26.48,-0.26,26.8,-0.39,27.79,-0.55,26.75,-0.51 -2021-04-01,24.89,-0.8,26.96,-0.65,28.47,-0.21,27.4,-0.49 diff --git a/core/pandas/pandas_fullNotebook.ipynb b/core/pandas/pandas_fullNotebook.ipynb index 1781edbdc..666e1c0c4 100644 --- a/core/pandas/pandas_fullNotebook.ipynb +++ b/core/pandas/pandas_fullNotebook.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "1d7850d7", + "id": "9f59d3f1", "metadata": {}, "source": [ "
\"pandas
\n", @@ -24,7 +24,7 @@ }, { "cell_type": "markdown", - "id": "449d3086-2fa1-4520-a390-8ba043db7258", + "id": "b8627bb7", "metadata": {}, "source": [ "
\n", @@ -33,17 +33,18 @@ }, { "cell_type": "code", - "execution_count": 1, - "id": "0912eaec", + "execution_count": null, + "id": "daf58736", "metadata": {}, "outputs": [], "source": [ - "import pandas as pd" + "import pandas as pd\n", + "from pythia_datasets import DATASETS # Project Pythia's custom store of example data" ] }, { "cell_type": "markdown", - "id": "85f7c6a5", + "id": "dab3da7f", "metadata": {}, "source": [ "## The pandas [`DataFrame`](https://pandas.pydata.org/docs/user_guide/dsintro.html#dataframe)...\n", @@ -56,19 +57,47 @@ "Let's take a look by reading in some `.csv` data, which comes from the NCDC teleconnections database, including various El Niño Southern Oscillation (ENSO) indices! [[ref](https://www.ncdc.noaa.gov/teleconnections/enso/indicators/sst/)]." ] }, + { + "cell_type": "markdown", + "id": "1f2329c8", + "metadata": {}, + "source": [ + "
\n", + " Tip: Here we're getting the data from Project Pythia's custom library of example data, which we already imported above with from pythia_datasets import DATASETS. The DATASETS.fetch() method will automatically download and cache our example data file enso_data.csv locally.\n", + "
" + ] + }, { "cell_type": "code", - "execution_count": 2, - "id": "ed076336-6bb7-4008-ba1c-451f08b9b31f", + "execution_count": null, + "id": "0be820cd", "metadata": {}, "outputs": [], "source": [ - "df = pd.read_csv('enso_data.csv')" + "filepath = DATASETS.fetch('enso_data.csv')" ] }, { "cell_type": "markdown", - "id": "ecd8e8f4-2857-43e7-a6c3-8484f36e2d8f", + "id": "68316c6c", + "metadata": {}, + "source": [ + "Once we have a valid path to a data file that Pandas knows how to read, we can open it like this:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e99652d5", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_csv(filepath)" + ] + }, + { + "cell_type": "markdown", + "id": "ae9dcbbd", "metadata": {}, "source": [ "If we print out our dataframe, you will notice that is text based, which is okay, but not the \"best\" looking output" @@ -76,51 +105,17 @@ }, { "cell_type": "code", - "execution_count": 3, - "id": "fd65e146-f213-4156-859c-1f3b30c5ea24", + "execution_count": null, + "id": "25a23571", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " datetime Nino12 Nino12anom Nino3 Nino3anom Nino4 Nino4anom \\\n", - "0 1982-01-01 24.29 -0.17 25.87 0.24 28.30 0.00 \n", - "1 1982-02-01 25.49 -0.58 26.38 0.01 28.21 0.11 \n", - "2 1982-03-01 25.21 -1.31 26.98 -0.16 28.41 0.22 \n", - "3 1982-04-01 24.50 -0.97 27.68 0.18 28.92 0.42 \n", - "4 1982-05-01 23.97 -0.23 27.79 0.71 29.49 0.70 \n", - ".. ... ... ... ... ... ... ... \n", - "467 2020-12-01 22.16 -0.60 24.38 -0.83 27.65 -0.95 \n", - "468 2021-01-01 23.89 -0.64 25.06 -0.55 27.10 -1.25 \n", - "469 2021-02-01 25.55 -0.66 25.80 -0.57 27.20 -1.00 \n", - "470 2021-03-01 26.48 -0.26 26.80 -0.39 27.79 -0.55 \n", - "471 2021-04-01 24.89 -0.80 26.96 -0.65 28.47 -0.21 \n", - "\n", - " Nino34 Nino34anom \n", - "0 26.72 0.15 \n", - "1 26.70 -0.02 \n", - "2 27.20 -0.02 \n", - "3 28.02 0.24 \n", - "4 28.54 0.69 \n", - ".. ... ... \n", - "467 25.53 -1.12 \n", - "468 25.58 -0.99 \n", - "469 25.81 -0.92 \n", - "470 26.75 -0.51 \n", - "471 27.40 -0.49 \n", - "\n", - "[472 rows x 9 columns]\n" - ] - } - ], + "outputs": [], "source": [ "print(df)" ] }, { "cell_type": "markdown", - "id": "11e7d697-f5ae-4487-a74c-2406afcdfafb", + "id": "f22bb442", "metadata": {}, "source": [ "Instead, if we just use the pandas dataframe itself (without wrapping it in `print`), we have a nicely rendered table which is native to pandas and Jupyter Notebooks. See how much nicer that looks?" @@ -128,222 +123,17 @@ }, { "cell_type": "code", - "execution_count": 4, - "id": "4ff69abc", + "execution_count": null, + "id": "b8942e69", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
datetimeNino12Nino12anomNino3Nino3anomNino4Nino4anomNino34Nino34anom
01982-01-0124.29-0.1725.870.2428.300.0026.720.15
11982-02-0125.49-0.5826.380.0128.210.1126.70-0.02
21982-03-0125.21-1.3126.98-0.1628.410.2227.20-0.02
31982-04-0124.50-0.9727.680.1828.920.4228.020.24
41982-05-0123.97-0.2327.790.7129.490.7028.540.69
..............................
4672020-12-0122.16-0.6024.38-0.8327.65-0.9525.53-1.12
4682021-01-0123.89-0.6425.06-0.5527.10-1.2525.58-0.99
4692021-02-0125.55-0.6625.80-0.5727.20-1.0025.81-0.92
4702021-03-0126.48-0.2626.80-0.3927.79-0.5526.75-0.51
4712021-04-0124.89-0.8026.96-0.6528.47-0.2127.40-0.49
\n", - "

472 rows × 9 columns

\n", - "
" - ], - "text/plain": [ - " datetime Nino12 Nino12anom Nino3 Nino3anom Nino4 Nino4anom \\\n", - "0 1982-01-01 24.29 -0.17 25.87 0.24 28.30 0.00 \n", - "1 1982-02-01 25.49 -0.58 26.38 0.01 28.21 0.11 \n", - "2 1982-03-01 25.21 -1.31 26.98 -0.16 28.41 0.22 \n", - "3 1982-04-01 24.50 -0.97 27.68 0.18 28.92 0.42 \n", - "4 1982-05-01 23.97 -0.23 27.79 0.71 29.49 0.70 \n", - ".. ... ... ... ... ... ... ... \n", - "467 2020-12-01 22.16 -0.60 24.38 -0.83 27.65 -0.95 \n", - "468 2021-01-01 23.89 -0.64 25.06 -0.55 27.10 -1.25 \n", - "469 2021-02-01 25.55 -0.66 25.80 -0.57 27.20 -1.00 \n", - "470 2021-03-01 26.48 -0.26 26.80 -0.39 27.79 -0.55 \n", - "471 2021-04-01 24.89 -0.80 26.96 -0.65 28.47 -0.21 \n", - "\n", - " Nino34 Nino34anom \n", - "0 26.72 0.15 \n", - "1 26.70 -0.02 \n", - "2 27.20 -0.02 \n", - "3 28.02 0.24 \n", - "4 28.54 0.69 \n", - ".. ... ... \n", - "467 25.53 -1.12 \n", - "468 25.58 -0.99 \n", - "469 25.81 -0.92 \n", - "470 26.75 -0.51 \n", - "471 27.40 -0.49 \n", - "\n", - "[472 rows x 9 columns]" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df" ] }, { "cell_type": "markdown", - "id": "03aa6062-ce17-4e9e-97e7-afd4930faabe", + "id": "377d4803", "metadata": {}, "source": [ "The `index` within pandas is essentially a list of the unique row IDs, which by default, is a list of sequential integers which start at 0" @@ -351,28 +141,17 @@ }, { "cell_type": "code", - "execution_count": 5, - "id": "36fff562", + "execution_count": null, + "id": "cde6999b", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RangeIndex(start=0, stop=472, step=1)" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.index" ] }, { "cell_type": "markdown", - "id": "407c2b57", + "id": "8af49ac9", "metadata": {}, "source": [ "Our indexing column isn't particularly helpful currently. Pandas is clever! A few optional keyword arguments later, and..." @@ -380,253 +159,29 @@ }, { "cell_type": "code", - "execution_count": 6, - "id": "a8b10c82", + "execution_count": null, + "id": "b4657f7e", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Nino12Nino12anomNino3Nino3anomNino4Nino4anomNino34Nino34anom
datetime
1982-01-0124.29-0.1725.870.2428.300.0026.720.15
1982-02-0125.49-0.5826.380.0128.210.1126.70-0.02
1982-03-0125.21-1.3126.98-0.1628.410.2227.20-0.02
1982-04-0124.50-0.9727.680.1828.920.4228.020.24
1982-05-0123.97-0.2327.790.7129.490.7028.540.69
...........................
2020-12-0122.16-0.6024.38-0.8327.65-0.9525.53-1.12
2021-01-0123.89-0.6425.06-0.5527.10-1.2525.58-0.99
2021-02-0125.55-0.6625.80-0.5727.20-1.0025.81-0.92
2021-03-0126.48-0.2626.80-0.3927.79-0.5526.75-0.51
2021-04-0124.89-0.8026.96-0.6528.47-0.2127.40-0.49
\n", - "

472 rows × 8 columns

\n", - "
" - ], - "text/plain": [ - " Nino12 Nino12anom Nino3 Nino3anom Nino4 Nino4anom Nino34 \\\n", - "datetime \n", - "1982-01-01 24.29 -0.17 25.87 0.24 28.30 0.00 26.72 \n", - "1982-02-01 25.49 -0.58 26.38 0.01 28.21 0.11 26.70 \n", - "1982-03-01 25.21 -1.31 26.98 -0.16 28.41 0.22 27.20 \n", - "1982-04-01 24.50 -0.97 27.68 0.18 28.92 0.42 28.02 \n", - "1982-05-01 23.97 -0.23 27.79 0.71 29.49 0.70 28.54 \n", - "... ... ... ... ... ... ... ... \n", - "2020-12-01 22.16 -0.60 24.38 -0.83 27.65 -0.95 25.53 \n", - "2021-01-01 23.89 -0.64 25.06 -0.55 27.10 -1.25 25.58 \n", - "2021-02-01 25.55 -0.66 25.80 -0.57 27.20 -1.00 25.81 \n", - "2021-03-01 26.48 -0.26 26.80 -0.39 27.79 -0.55 26.75 \n", - "2021-04-01 24.89 -0.80 26.96 -0.65 28.47 -0.21 27.40 \n", - "\n", - " Nino34anom \n", - "datetime \n", - "1982-01-01 0.15 \n", - "1982-02-01 -0.02 \n", - "1982-03-01 -0.02 \n", - "1982-04-01 0.24 \n", - "1982-05-01 0.69 \n", - "... ... \n", - "2020-12-01 -1.12 \n", - "2021-01-01 -0.99 \n", - "2021-02-01 -0.92 \n", - "2021-03-01 -0.51 \n", - "2021-04-01 -0.49 \n", - "\n", - "[472 rows x 8 columns]" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "df = pd.read_csv('enso_data.csv', index_col=0, parse_dates=True)\n", + "df = pd.read_csv(filepath, index_col=0, parse_dates=True)\n", "\n", "df" ] }, { "cell_type": "code", - "execution_count": 7, - "id": "d648b36a", + "execution_count": null, + "id": "b0d3ae28", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "DatetimeIndex(['1982-01-01', '1982-02-01', '1982-03-01', '1982-04-01',\n", - " '1982-05-01', '1982-06-01', '1982-07-01', '1982-08-01',\n", - " '1982-09-01', '1982-10-01',\n", - " ...\n", - " '2020-07-01', '2020-08-01', '2020-09-01', '2020-10-01',\n", - " '2020-11-01', '2020-12-01', '2021-01-01', '2021-02-01',\n", - " '2021-03-01', '2021-04-01'],\n", - " dtype='datetime64[ns]', name='datetime', length=472, freq=None)" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.index" ] }, { "cell_type": "markdown", - "id": "1757f632", + "id": "8d26ed71", "metadata": {}, "source": [ "... now we have our data helpfully organized by a proper `datetime`-like object. Each of our multiple columns of data can now be referenced by their date! This sneak preview at the pandas `DatetimeIndex` also unlocks for us much of pandas most useful time series functionality. Don't worry, we'll get there. What are the actual columns of data we've read in here?" @@ -634,30 +189,17 @@ }, { "cell_type": "code", - "execution_count": 8, - "id": "33a95505", + "execution_count": null, + "id": "847347f8", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Index(['Nino12', 'Nino12anom', 'Nino3', 'Nino3anom', 'Nino4', 'Nino4anom',\n", - " 'Nino34', 'Nino34anom'],\n", - " dtype='object')" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.columns" ] }, { "cell_type": "markdown", - "id": "c3ab938b", + "id": "08d3b2fb", "metadata": {}, "source": [ "## The pandas [`Series`](https://pandas.pydata.org/docs/user_guide/dsintro.html#series)...\n", @@ -671,40 +213,17 @@ }, { "cell_type": "code", - "execution_count": 9, - "id": "dc4d61cf", + "execution_count": null, + "id": "ee085815", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "datetime\n", - "1982-01-01 26.72\n", - "1982-02-01 26.70\n", - "1982-03-01 27.20\n", - "1982-04-01 28.02\n", - "1982-05-01 28.54\n", - " ... \n", - "2020-12-01 25.53\n", - "2021-01-01 25.58\n", - "2021-02-01 25.81\n", - "2021-03-01 26.75\n", - "2021-04-01 27.40\n", - "Name: Nino34, Length: 472, dtype: float64" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df[\"Nino34\"]" ] }, { "cell_type": "markdown", - "id": "2b73e16d-f921-48c4-91f7-6eb2c8bd7b08", + "id": "2fcc97fa", "metadata": {}, "source": [ "
\n", @@ -713,40 +232,17 @@ }, { "cell_type": "code", - "execution_count": 10, - "id": "c4849ee1", + "execution_count": null, + "id": "7d46cbb9", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "datetime\n", - "1982-01-01 26.72\n", - "1982-02-01 26.70\n", - "1982-03-01 27.20\n", - "1982-04-01 28.02\n", - "1982-05-01 28.54\n", - " ... \n", - "2020-12-01 25.53\n", - "2021-01-01 25.58\n", - "2021-02-01 25.81\n", - "2021-03-01 26.75\n", - "2021-04-01 27.40\n", - "Name: Nino34, Length: 472, dtype: float64" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.Nino34" ] }, { "cell_type": "markdown", - "id": "3bed7402", + "id": "c2a10249", "metadata": {}, "source": [ "## Slicing and Dicing the `DataFrame` and `Series`" @@ -754,7 +250,7 @@ }, { "cell_type": "markdown", - "id": "9b0bdcaa", + "id": "e38faac9", "metadata": {}, "source": [ "We will expand on what you just saw, soon! Importantly,\n", @@ -768,33 +264,10 @@ }, { "cell_type": "code", - "execution_count": 11, - "id": "bdb5ebff", + "execution_count": null, + "id": "ec9ed333", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "datetime\n", - "1982-01-01 26.72\n", - "1982-02-01 26.70\n", - "1982-03-01 27.20\n", - "1982-04-01 28.02\n", - "1982-05-01 28.54\n", - " ... \n", - "2020-12-01 25.53\n", - "2021-01-01 25.58\n", - "2021-02-01 25.81\n", - "2021-03-01 26.75\n", - "2021-04-01 27.40\n", - "Name: Nino34, Length: 472, dtype: float64" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "nino34_series = df[\"Nino34\"]\n", "\n", @@ -803,7 +276,7 @@ }, { "cell_type": "markdown", - "id": "75bc2403", + "id": "c84a81b9", "metadata": {}, "source": [ "`Series` can be indexed, selected, and subset as both `ndarray`-like," @@ -811,28 +284,17 @@ }, { "cell_type": "code", - "execution_count": 12, - "id": "37d20e44", + "execution_count": null, + "id": "39bb0ae3", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "28.02" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "nino34_series[3]" ] }, { "cell_type": "markdown", - "id": "6e7ac685", + "id": "a1a55a7c", "metadata": {}, "source": [ "and `dict`-like, using labels" @@ -840,28 +302,17 @@ }, { "cell_type": "code", - "execution_count": 13, - "id": "f64e5695", + "execution_count": null, + "id": "62006988", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "28.02" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "nino34_series[\"1982-04-01\"]" ] }, { "cell_type": "markdown", - "id": "686a3ecf", + "id": "cb17f245", "metadata": {}, "source": [ "and these can be extended in ways that you might expect, but perhaps also in unexpected ways:" @@ -869,7 +320,7 @@ }, { "cell_type": "markdown", - "id": "251cb40a-06cd-4bfa-b959-a434e0e601eb", + "id": "ae740b50", "metadata": {}, "source": [ "### Numpy-like Interval Slices" @@ -877,7 +328,7 @@ }, { "cell_type": "markdown", - "id": "ee4a8bfd-e63c-4bf6-9b43-addfeca9b4b2", + "id": "85123793", "metadata": {}, "source": [ "
\n", @@ -887,41 +338,17 @@ }, { "cell_type": "code", - "execution_count": 14, - "id": "2ddc17a0", + "execution_count": null, + "id": "221e798d", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "datetime\n", - "1982-01-01 26.72\n", - "1982-02-01 26.70\n", - "1982-03-01 27.20\n", - "1982-04-01 28.02\n", - "1982-05-01 28.54\n", - "1982-06-01 28.75\n", - "1982-07-01 28.10\n", - "1982-08-01 27.93\n", - "1982-09-01 28.11\n", - "1982-10-01 28.64\n", - "1982-11-01 28.81\n", - "1982-12-01 29.21\n", - "Name: Nino34, dtype: float64" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "nino34_series[0:12]" ] }, { "cell_type": "markdown", - "id": "606352a3-6596-4683-ab9c-c72a0bf609d1", + "id": "6281e3a6", "metadata": {}, "source": [ "### Label-based Slicing" @@ -929,7 +356,7 @@ }, { "cell_type": "markdown", - "id": "849645a7-d3a2-4a61-9cf9-52a765086049", + "id": "b6dceb40", "metadata": {}, "source": [ "
\n", @@ -938,41 +365,17 @@ }, { "cell_type": "code", - "execution_count": 15, - "id": "1c31803c", + "execution_count": null, + "id": "f7a06967", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "datetime\n", - "1982-01-01 26.72\n", - "1982-02-01 26.70\n", - "1982-03-01 27.20\n", - "1982-04-01 28.02\n", - "1982-05-01 28.54\n", - "1982-06-01 28.75\n", - "1982-07-01 28.10\n", - "1982-08-01 27.93\n", - "1982-09-01 28.11\n", - "1982-10-01 28.64\n", - "1982-11-01 28.81\n", - "1982-12-01 29.21\n", - "Name: Nino34, dtype: float64" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "nino34_series[\"1982-01-01\":\"1982-12-01\"]" ] }, { "cell_type": "markdown", - "id": "057795dd-ac38-4812-a04c-25a9516931bc", + "id": "84edfd6f", "metadata": {}, "source": [ "### Another Way of Slicing" @@ -980,41 +383,17 @@ }, { "cell_type": "code", - "execution_count": 16, - "id": "a629daf5", + "execution_count": null, + "id": "771d6f04", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "datetime\n", - "1982-01-01 26.72\n", - "1982-02-01 26.70\n", - "1982-03-01 27.20\n", - "1982-04-01 28.02\n", - "1982-05-01 28.54\n", - "1982-06-01 28.75\n", - "1982-07-01 28.10\n", - "1982-08-01 27.93\n", - "1982-09-01 28.11\n", - "1982-10-01 28.64\n", - "1982-11-01 28.81\n", - "1982-12-01 29.21\n", - "Name: Nino34, dtype: float64" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "nino34_series[slice(\"1982-01-01\", \"1982-12-01\")]" ] }, { "cell_type": "markdown", - "id": "fab92608", + "id": "9798abf4", "metadata": {}, "source": [ "### Using `.iloc` and `.loc` to index\n", @@ -1024,117 +403,47 @@ }, { "cell_type": "code", - "execution_count": 17, - "id": "8828ebae", + "execution_count": null, + "id": "d5eb9de2", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "28.02" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "nino34_series.iloc[3]" ] }, { "cell_type": "code", - "execution_count": 18, - "id": "d37ca35a", + "execution_count": null, + "id": "8d0bc3e8", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "datetime\n", - "1982-01-01 26.72\n", - "1982-02-01 26.70\n", - "1982-03-01 27.20\n", - "1982-04-01 28.02\n", - "1982-05-01 28.54\n", - "1982-06-01 28.75\n", - "1982-07-01 28.10\n", - "1982-08-01 27.93\n", - "1982-09-01 28.11\n", - "1982-10-01 28.64\n", - "1982-11-01 28.81\n", - "1982-12-01 29.21\n", - "Name: Nino34, dtype: float64" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "nino34_series.iloc[0:12]" ] }, { "cell_type": "code", - "execution_count": 19, - "id": "1cd4b99d", + "execution_count": null, + "id": "59a10070", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "28.02" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "nino34_series.loc[\"1982-04-01\"]" ] }, { "cell_type": "code", - "execution_count": 20, - "id": "df53360c", + "execution_count": null, + "id": "3e2b3fc1", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "datetime\n", - "1982-01-01 26.72\n", - "1982-02-01 26.70\n", - "1982-03-01 27.20\n", - "1982-04-01 28.02\n", - "1982-05-01 28.54\n", - "1982-06-01 28.75\n", - "1982-07-01 28.10\n", - "1982-08-01 27.93\n", - "1982-09-01 28.11\n", - "1982-10-01 28.64\n", - "1982-11-01 28.81\n", - "1982-12-01 29.21\n", - "Name: Nino34, dtype: float64" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "nino34_series.loc[\"1982-01-01\":\"1982-12-01\"]" ] }, { "cell_type": "markdown", - "id": "67be0464", + "id": "44824b21", "metadata": {}, "source": [ "These capabilities extend back to our original `DataFrame`, as well! :" @@ -1142,7 +451,7 @@ }, { "cell_type": "markdown", - "id": "183e94a7-36dd-4f93-a8fe-e51b58ca0c15", + "id": "481cde44", "metadata": {}, "source": [ "
\n", @@ -1152,114 +461,47 @@ }, { "cell_type": "code", - "execution_count": 21, - "id": "6d0c9bd7", + "execution_count": null, + "id": "b8971371", "metadata": { "tags": [ "raises-exception" ] }, - "outputs": [ - { - "ename": "KeyError", - "evalue": "'1982-01-01'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m~/anaconda3/envs/pythia-book-dev/lib/python3.8/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 3079\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3080\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasted_key\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3081\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", - "\u001b[0;31mKeyError\u001b[0m: '1982-01-01'", - "\nThe above exception was the direct cause of the following exception:\n", - "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"1982-01-01\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/anaconda3/envs/pythia-book-dev/lib/python3.8/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 3022\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnlevels\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3023\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_getitem_multilevel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3024\u001b[0;31m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3025\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mis_integer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3026\u001b[0m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/anaconda3/envs/pythia-book-dev/lib/python3.8/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 3080\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasted_key\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3081\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3082\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3083\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3084\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mtolerance\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mKeyError\u001b[0m: '1982-01-01'" - ] - } - ], + "outputs": [], "source": [ "df[\"1982-01-01\"]" ] }, { "cell_type": "code", - "execution_count": 22, - "id": "006ba58a", + "execution_count": null, + "id": "3c147c06", "metadata": { "tags": [ "raises-exception" ] }, - "outputs": [ - { - "ename": "KeyError", - "evalue": "0", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m~/anaconda3/envs/pythia-book-dev/lib/python3.8/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 3079\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3080\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasted_key\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3081\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", - "\u001b[0;31mKeyError\u001b[0m: 0", - "\nThe above exception was the direct cause of the following exception:\n", - "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdf\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/anaconda3/envs/pythia-book-dev/lib/python3.8/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 3022\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnlevels\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3023\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_getitem_multilevel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3024\u001b[0;31m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3025\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mis_integer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3026\u001b[0m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/anaconda3/envs/pythia-book-dev/lib/python3.8/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 3080\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasted_key\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3081\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3082\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3083\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3084\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mtolerance\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mKeyError\u001b[0m: 0" - ] - } - ], + "outputs": [], "source": [ "df[0]" ] }, { "cell_type": "code", - "execution_count": 23, - "id": "94bff713", + "execution_count": null, + "id": "0b05470d", "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "datetime\n", - "1982-01-01 26.72\n", - "1982-02-01 26.70\n", - "1982-03-01 27.20\n", - "1982-04-01 28.02\n", - "1982-05-01 28.54\n", - " ... \n", - "2020-12-01 25.53\n", - "2021-01-01 25.58\n", - "2021-02-01 25.81\n", - "2021-03-01 26.75\n", - "2021-04-01 27.40\n", - "Name: Nino34, Length: 472, dtype: float64" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df[\"Nino34\"]" ] }, { "cell_type": "markdown", - "id": "0d7f203e", + "id": "d4e6213d", "metadata": {}, "source": [ "With this plus our knowledge of the `Series` `df[\"Nino34\"]` gives us, we can chain our brackets to pull out any value from any of our columns in `df`." @@ -1267,49 +509,27 @@ }, { "cell_type": "code", - "execution_count": 24, - "id": "e8b04193", + "execution_count": null, + "id": "c61fa6d4", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "28.02" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df[\"Nino34\"][\"1982-04-01\"] # selecting the Series, then selecting a label within" ] }, { "cell_type": "code", - "execution_count": 25, - "id": "7ca8eadc", + "execution_count": null, + "id": "3bd7cf95", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "28.02" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df[\"Nino34\"][3]" ] }, { "cell_type": "markdown", - "id": "09d33515", + "id": "afb0d6ef", "metadata": {}, "source": [ "However, this is not a pandas-preferred way to index and subset our data, and has limited capabilities for us. As we touched on before, `.loc` and `.iloc` give us more to work with, and their functionality grows further for `df`." @@ -1317,28 +537,17 @@ }, { "cell_type": "code", - "execution_count": 26, - "id": "6c9ac325", + "execution_count": null, + "id": "9fb5df7b", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "28.02" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.loc[\"1982-04-01\", \"Nino34\"] # note [, ] ordering" ] }, { "cell_type": "markdown", - "id": "e7cfdd38", + "id": "e710252f", "metadata": {}, "source": [ "These allow us to pull out entire rows of `df`," @@ -1346,517 +555,47 @@ }, { "cell_type": "code", - "execution_count": 27, - "id": "f51c7741", + "execution_count": null, + "id": "aad4fde6", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Nino12 24.50\n", - "Nino12anom -0.97\n", - "Nino3 27.68\n", - "Nino3anom 0.18\n", - "Nino4 28.92\n", - "Nino4anom 0.42\n", - "Nino34 28.02\n", - "Nino34anom 0.24\n", - "Name: 1982-04-01 00:00:00, dtype: float64" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.loc[\"1982-04-01\"]" ] }, { "cell_type": "code", - "execution_count": 28, - "id": "e42c3508", + "execution_count": null, + "id": "f93737ba", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Nino12Nino12anomNino3Nino3anomNino4Nino4anomNino34Nino34anom
datetime
1982-01-0124.29-0.1725.870.2428.300.0026.720.15
1982-02-0125.49-0.5826.380.0128.210.1126.70-0.02
1982-03-0125.21-1.3126.98-0.1628.410.2227.20-0.02
1982-04-0124.50-0.9727.680.1828.920.4228.020.24
1982-05-0123.97-0.2327.790.7129.490.7028.540.69
1982-06-0122.890.0727.461.0329.760.9228.751.10
1982-07-0122.470.8726.440.8229.380.5828.100.88
1982-08-0121.751.1026.151.1629.040.3627.931.11
1982-09-0121.801.4426.521.6729.160.4728.111.39
1982-10-0122.942.1227.112.1929.380.7228.641.95
1982-11-0124.593.0027.622.6429.230.6028.812.16
1982-12-0126.133.3428.393.2529.150.6629.212.64
\n", - "
" - ], - "text/plain": [ - " Nino12 Nino12anom Nino3 Nino3anom Nino4 Nino4anom Nino34 \\\n", - "datetime \n", - "1982-01-01 24.29 -0.17 25.87 0.24 28.30 0.00 26.72 \n", - "1982-02-01 25.49 -0.58 26.38 0.01 28.21 0.11 26.70 \n", - "1982-03-01 25.21 -1.31 26.98 -0.16 28.41 0.22 27.20 \n", - "1982-04-01 24.50 -0.97 27.68 0.18 28.92 0.42 28.02 \n", - "1982-05-01 23.97 -0.23 27.79 0.71 29.49 0.70 28.54 \n", - "1982-06-01 22.89 0.07 27.46 1.03 29.76 0.92 28.75 \n", - "1982-07-01 22.47 0.87 26.44 0.82 29.38 0.58 28.10 \n", - "1982-08-01 21.75 1.10 26.15 1.16 29.04 0.36 27.93 \n", - "1982-09-01 21.80 1.44 26.52 1.67 29.16 0.47 28.11 \n", - "1982-10-01 22.94 2.12 27.11 2.19 29.38 0.72 28.64 \n", - "1982-11-01 24.59 3.00 27.62 2.64 29.23 0.60 28.81 \n", - "1982-12-01 26.13 3.34 28.39 3.25 29.15 0.66 29.21 \n", - "\n", - " Nino34anom \n", - "datetime \n", - "1982-01-01 0.15 \n", - "1982-02-01 -0.02 \n", - "1982-03-01 -0.02 \n", - "1982-04-01 0.24 \n", - "1982-05-01 0.69 \n", - "1982-06-01 1.10 \n", - "1982-07-01 0.88 \n", - "1982-08-01 1.11 \n", - "1982-09-01 1.39 \n", - "1982-10-01 1.95 \n", - "1982-11-01 2.16 \n", - "1982-12-01 2.64 " - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.loc[\"1982-01-01\":\"1982-12-01\"]" ] }, { "cell_type": "code", - "execution_count": 29, - "id": "dc66c1d6", + "execution_count": null, + "id": "6c23cbca", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Nino12 24.50\n", - "Nino12anom -0.97\n", - "Nino3 27.68\n", - "Nino3anom 0.18\n", - "Nino4 28.92\n", - "Nino4anom 0.42\n", - "Nino34 28.02\n", - "Nino34anom 0.24\n", - "Name: 1982-04-01 00:00:00, dtype: float64" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.iloc[3]" ] }, { "cell_type": "code", - "execution_count": 30, - "id": "9e1fc528", + "execution_count": null, + "id": "22c07d7d", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Nino12Nino12anomNino3Nino3anomNino4Nino4anomNino34Nino34anom
datetime
1982-01-0124.29-0.1725.870.2428.300.0026.720.15
1982-02-0125.49-0.5826.380.0128.210.1126.70-0.02
1982-03-0125.21-1.3126.98-0.1628.410.2227.20-0.02
1982-04-0124.50-0.9727.680.1828.920.4228.020.24
1982-05-0123.97-0.2327.790.7129.490.7028.540.69
1982-06-0122.890.0727.461.0329.760.9228.751.10
1982-07-0122.470.8726.440.8229.380.5828.100.88
1982-08-0121.751.1026.151.1629.040.3627.931.11
1982-09-0121.801.4426.521.6729.160.4728.111.39
1982-10-0122.942.1227.112.1929.380.7228.641.95
1982-11-0124.593.0027.622.6429.230.6028.812.16
1982-12-0126.133.3428.393.2529.150.6629.212.64
\n", - "
" - ], - "text/plain": [ - " Nino12 Nino12anom Nino3 Nino3anom Nino4 Nino4anom Nino34 \\\n", - "datetime \n", - "1982-01-01 24.29 -0.17 25.87 0.24 28.30 0.00 26.72 \n", - "1982-02-01 25.49 -0.58 26.38 0.01 28.21 0.11 26.70 \n", - "1982-03-01 25.21 -1.31 26.98 -0.16 28.41 0.22 27.20 \n", - "1982-04-01 24.50 -0.97 27.68 0.18 28.92 0.42 28.02 \n", - "1982-05-01 23.97 -0.23 27.79 0.71 29.49 0.70 28.54 \n", - "1982-06-01 22.89 0.07 27.46 1.03 29.76 0.92 28.75 \n", - "1982-07-01 22.47 0.87 26.44 0.82 29.38 0.58 28.10 \n", - "1982-08-01 21.75 1.10 26.15 1.16 29.04 0.36 27.93 \n", - "1982-09-01 21.80 1.44 26.52 1.67 29.16 0.47 28.11 \n", - "1982-10-01 22.94 2.12 27.11 2.19 29.38 0.72 28.64 \n", - "1982-11-01 24.59 3.00 27.62 2.64 29.23 0.60 28.81 \n", - "1982-12-01 26.13 3.34 28.39 3.25 29.15 0.66 29.21 \n", - "\n", - " Nino34anom \n", - "datetime \n", - "1982-01-01 0.15 \n", - "1982-02-01 -0.02 \n", - "1982-03-01 -0.02 \n", - "1982-04-01 0.24 \n", - "1982-05-01 0.69 \n", - "1982-06-01 1.10 \n", - "1982-07-01 0.88 \n", - "1982-08-01 1.11 \n", - "1982-09-01 1.39 \n", - "1982-10-01 1.95 \n", - "1982-11-01 2.16 \n", - "1982-12-01 2.64 " - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.iloc[0:12]" ] }, { "cell_type": "markdown", - "id": "c1aa8b6a", + "id": "4c2ed15e", "metadata": {}, "source": [ "Even further," @@ -1864,155 +603,10 @@ }, { "cell_type": "code", - "execution_count": 31, - "id": "abb48564", + "execution_count": null, + "id": "8390a35b", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Nino12Nino3Nino4Nino34
datetime
1982-01-0124.2925.8728.3026.72
1982-02-0125.4926.3828.2126.70
1982-03-0125.2126.9828.4127.20
1982-04-0124.5027.6828.9228.02
1982-05-0123.9727.7929.4928.54
1982-06-0122.8927.4629.7628.75
1982-07-0122.4726.4429.3828.10
1982-08-0121.7526.1529.0427.93
1982-09-0121.8026.5229.1628.11
1982-10-0122.9427.1129.3828.64
1982-11-0124.5927.6229.2328.81
1982-12-0126.1328.3929.1529.21
\n", - "
" - ], - "text/plain": [ - " Nino12 Nino3 Nino4 Nino34\n", - "datetime \n", - "1982-01-01 24.29 25.87 28.30 26.72\n", - "1982-02-01 25.49 26.38 28.21 26.70\n", - "1982-03-01 25.21 26.98 28.41 27.20\n", - "1982-04-01 24.50 27.68 28.92 28.02\n", - "1982-05-01 23.97 27.79 29.49 28.54\n", - "1982-06-01 22.89 27.46 29.76 28.75\n", - "1982-07-01 22.47 26.44 29.38 28.10\n", - "1982-08-01 21.75 26.15 29.04 27.93\n", - "1982-09-01 21.80 26.52 29.16 28.11\n", - "1982-10-01 22.94 27.11 29.38 28.64\n", - "1982-11-01 24.59 27.62 29.23 28.81\n", - "1982-12-01 26.13 28.39 29.15 29.21" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.loc[\n", " \"1982-01-01\":\"1982-12-01\", # slice of rows\n", @@ -2022,7 +616,7 @@ }, { "cell_type": "markdown", - "id": "317de007-32dd-435b-be58-7af6c5739f1a", + "id": "e65349af", "metadata": {}, "source": [ "
\n", @@ -2031,7 +625,7 @@ }, { "cell_type": "markdown", - "id": "848ba67d-490d-4d6a-8538-a9f59ff92b9c", + "id": "2e2739dc", "metadata": {}, "source": [ "## Exploratory Data Analysis\n", @@ -2042,277 +636,27 @@ }, { "cell_type": "code", - "execution_count": 32, - "id": "d14272a0-fba2-426c-85f3-84640df66003", + "execution_count": null, + "id": "3c11b92a", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Nino12Nino12anomNino3Nino3anomNino4Nino4anomNino34Nino34anom
datetime
1982-01-0124.29-0.1725.870.2428.300.0026.720.15
1982-02-0125.49-0.5826.380.0128.210.1126.70-0.02
1982-03-0125.21-1.3126.98-0.1628.410.2227.20-0.02
1982-04-0124.50-0.9727.680.1828.920.4228.020.24
1982-05-0123.97-0.2327.790.7129.490.7028.540.69
\n", - "
" - ], - "text/plain": [ - " Nino12 Nino12anom Nino3 Nino3anom Nino4 Nino4anom Nino34 \\\n", - "datetime \n", - "1982-01-01 24.29 -0.17 25.87 0.24 28.30 0.00 26.72 \n", - "1982-02-01 25.49 -0.58 26.38 0.01 28.21 0.11 26.70 \n", - "1982-03-01 25.21 -1.31 26.98 -0.16 28.41 0.22 27.20 \n", - "1982-04-01 24.50 -0.97 27.68 0.18 28.92 0.42 28.02 \n", - "1982-05-01 23.97 -0.23 27.79 0.71 29.49 0.70 28.54 \n", - "\n", - " Nino34anom \n", - "datetime \n", - "1982-01-01 0.15 \n", - "1982-02-01 -0.02 \n", - "1982-03-01 -0.02 \n", - "1982-04-01 0.24 \n", - "1982-05-01 0.69 " - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.head()" ] }, { "cell_type": "code", - "execution_count": 33, - "id": "64cb13f6-8f70-4e37-9c4c-16b5d9b6112f", + "execution_count": null, + "id": "3bf87294", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Nino12Nino12anomNino3Nino3anomNino4Nino4anomNino34Nino34anom
datetime
2020-12-0122.16-0.6024.38-0.8327.65-0.9525.53-1.12
2021-01-0123.89-0.6425.06-0.5527.10-1.2525.58-0.99
2021-02-0125.55-0.6625.80-0.5727.20-1.0025.81-0.92
2021-03-0126.48-0.2626.80-0.3927.79-0.5526.75-0.51
2021-04-0124.89-0.8026.96-0.6528.47-0.2127.40-0.49
\n", - "
" - ], - "text/plain": [ - " Nino12 Nino12anom Nino3 Nino3anom Nino4 Nino4anom Nino34 \\\n", - "datetime \n", - "2020-12-01 22.16 -0.60 24.38 -0.83 27.65 -0.95 25.53 \n", - "2021-01-01 23.89 -0.64 25.06 -0.55 27.10 -1.25 25.58 \n", - "2021-02-01 25.55 -0.66 25.80 -0.57 27.20 -1.00 25.81 \n", - "2021-03-01 26.48 -0.26 26.80 -0.39 27.79 -0.55 26.75 \n", - "2021-04-01 24.89 -0.80 26.96 -0.65 28.47 -0.21 27.40 \n", - "\n", - " Nino34anom \n", - "datetime \n", - "2020-12-01 -1.12 \n", - "2021-01-01 -0.99 \n", - "2021-02-01 -0.92 \n", - "2021-03-01 -0.51 \n", - "2021-04-01 -0.49 " - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.tail()" ] }, { "cell_type": "markdown", - "id": "0da2b376-8964-4b7b-b313-fa2ffb8ef372", + "id": "cba9f221", "metadata": {}, "source": [ "### Quick Plots of Your Data\n", @@ -2321,30 +665,17 @@ }, { "cell_type": "code", - "execution_count": 34, - "id": "7b09fdb4", + "execution_count": null, + "id": "bf317171", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "df.Nino34.plot();" ] }, { "cell_type": "markdown", - "id": "92800a25", + "id": "99c2c7a3", "metadata": {}, "source": [ "Before, we called `.plot()` which generated a single line plot. This is helpful, but there are other plots which can also help with understanding your data! Let's try using a histogram to understand distributions...\n", @@ -2354,30 +685,17 @@ }, { "cell_type": "code", - "execution_count": 35, - "id": "c4db0c16", + "execution_count": null, + "id": "5f85e2dd", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "df[['Nino12', 'Nino34']].plot.hist();" ] }, { "cell_type": "markdown", - "id": "db891ecb", + "id": "a4e07618", "metadata": {}, "source": [ "We can see some clear differences in the distributions, which is helpful! Another plot one might like to use would be a `boxplot`. Here, we replace `hist` with `box`" @@ -2385,30 +703,17 @@ }, { "cell_type": "code", - "execution_count": 36, - "id": "b353ed8b", + "execution_count": null, + "id": "6329d231", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "df[['Nino12', 'Nino34']].plot.box();" ] }, { "cell_type": "markdown", - "id": "6346ecd3", + "id": "c338385b", "metadata": {}, "source": [ "Here, we again see a clear difference in the distributions. These are not the only plots you can use within pandas! For more examples of plotting choices, check out [the pandas plot documentation](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.plot.html)" @@ -2416,7 +721,7 @@ }, { "cell_type": "markdown", - "id": "fd10d71d-63df-44d5-bca3-6eb436cfd68d", + "id": "69fc4078", "metadata": {}, "source": [ "#### Customize your Plot\n", @@ -2425,23 +730,10 @@ }, { "cell_type": "code", - "execution_count": 37, - "id": "cadb301b-2f22-4cff-9c58-bd8394e9e5fc", + "execution_count": null, + "id": "da22f990", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "df.Nino34.plot(\n", " color='black',\n", @@ -2454,7 +746,7 @@ }, { "cell_type": "markdown", - "id": "14ef06ef", + "id": "e7145ef6", "metadata": {}, "source": [ "This can be a great way to take a quick look at your data, but what if you wanted a more ***quantitative*** perspective? We can use the `describe` method on our `DataFrame`; this returns a table of summary statistics for all columns in the `DataFrame`\n", @@ -2466,168 +758,17 @@ }, { "cell_type": "code", - "execution_count": 38, - "id": "0b7011a6", + "execution_count": null, + "id": "3b5c27a8", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Nino12Nino12anomNino3Nino3anomNino4Nino4anomNino34Nino34anom
count472.000000472.000000472.000000472.000000472.000000472.000000472.000000472.000000
mean23.2096190.05972525.9365680.03942828.6250640.06381427.0767800.034894
std2.4315221.1575901.3496210.9654640.7554220.7094011.0630040.947936
min18.570000-2.10000023.030000-2.07000026.430000-1.87000024.270000-2.380000
25%21.152500-0.71250024.850000-0.60000028.140000-0.43000026.330000-0.572500
50%22.980000-0.16000025.885000-0.11500028.7600000.20500027.1000000.015000
75%25.3225000.51500026.9625000.51250029.1900000.63000027.7925000.565000
max29.1500004.62000029.1400003.62000030.3000001.67000029.6000002.950000
\n", - "
" - ], - "text/plain": [ - " Nino12 Nino12anom Nino3 Nino3anom Nino4 Nino4anom \\\n", - "count 472.000000 472.000000 472.000000 472.000000 472.000000 472.000000 \n", - "mean 23.209619 0.059725 25.936568 0.039428 28.625064 0.063814 \n", - "std 2.431522 1.157590 1.349621 0.965464 0.755422 0.709401 \n", - "min 18.570000 -2.100000 23.030000 -2.070000 26.430000 -1.870000 \n", - "25% 21.152500 -0.712500 24.850000 -0.600000 28.140000 -0.430000 \n", - "50% 22.980000 -0.160000 25.885000 -0.115000 28.760000 0.205000 \n", - "75% 25.322500 0.515000 26.962500 0.512500 29.190000 0.630000 \n", - "max 29.150000 4.620000 29.140000 3.620000 30.300000 1.670000 \n", - "\n", - " Nino34 Nino34anom \n", - "count 472.000000 472.000000 \n", - "mean 27.076780 0.034894 \n", - "std 1.063004 0.947936 \n", - "min 24.270000 -2.380000 \n", - "25% 26.330000 -0.572500 \n", - "50% 27.100000 0.015000 \n", - "75% 27.792500 0.565000 \n", - "max 29.600000 2.950000 " - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.describe()" ] }, { "cell_type": "markdown", - "id": "a09a3ca9", + "id": "a92bb8b3", "metadata": {}, "source": [ "You can look at specific statistics too, such as mean! Notice how the output is a `Series` (column) now" @@ -2635,36 +776,17 @@ }, { "cell_type": "code", - "execution_count": 39, - "id": "2a4b8b6a", + "execution_count": null, + "id": "db9e4a16", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Nino12 23.209619\n", - "Nino12anom 0.059725\n", - "Nino3 25.936568\n", - "Nino3anom 0.039428\n", - "Nino4 28.625064\n", - "Nino4anom 0.063814\n", - "Nino34 27.076780\n", - "Nino34anom 0.034894\n", - "dtype: float64" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.mean()" ] }, { "cell_type": "markdown", - "id": "c3ead9af", + "id": "1ff5aec7", "metadata": {}, "source": [ "If you are interested in a single column mean, subset for that and use `.mean`" @@ -2672,28 +794,17 @@ }, { "cell_type": "code", - "execution_count": 40, - "id": "2123223e", + "execution_count": null, + "id": "9aa38e59", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "27.07677966101695" - ] - }, - "execution_count": 40, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.Nino34.mean()" ] }, { "cell_type": "markdown", - "id": "678fde2f", + "id": "7295e7b0", "metadata": {}, "source": [ "### Subsetting Using the Datetime Column\n", @@ -2705,590 +816,10 @@ }, { "cell_type": "code", - "execution_count": 41, - "id": "8a82e067", + "execution_count": null, + "id": "a506724a", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Nino12Nino12anomNino3Nino3anomNino4Nino4anomNino34Nino34anom
datetime
1982-01-0124.29-0.1725.870.2428.300.0026.720.15
1983-01-0127.422.9628.923.2929.000.7029.362.79
1984-01-0124.18-0.2824.82-0.8127.64-0.6625.64-0.93
1985-01-0123.59-0.8724.51-1.1227.71-0.5925.43-1.14
1986-01-0124.610.1524.73-0.9028.11-0.1925.79-0.78
1987-01-0125.300.8426.691.0629.020.7227.911.34
1988-01-0124.640.1826.120.4929.130.8327.320.75
1989-01-0124.09-0.3724.15-1.4826.54-1.7624.53-2.04
1990-01-0124.02-0.4425.34-0.2928.560.2626.55-0.02
1991-01-0123.86-0.6025.650.0229.000.7027.010.44
1992-01-0124.830.3727.001.3729.060.7628.411.84
1993-01-0124.43-0.0325.56-0.0728.600.3026.690.12
1994-01-0124.32-0.1425.710.0828.470.1726.600.03
1995-01-0125.330.8726.340.7129.200.9027.550.98
1996-01-0123.84-0.6224.96-0.6727.92-0.3825.74-0.83
1997-01-0123.67-0.7924.70-0.9328.410.1125.96-0.61
1998-01-0128.223.7628.943.3129.010.7129.102.53
1999-01-0123.73-0.7324.41-1.2226.59-1.7124.90-1.67
2000-01-0123.86-0.6023.88-1.7526.96-1.3424.65-1.92
2001-01-0123.88-0.5824.99-0.6427.50-0.8025.74-0.83
2002-01-0123.64-0.8225.09-0.5428.810.5126.50-0.07
2003-01-0124.38-0.0826.380.7529.250.9527.761.19
2004-01-0124.600.1425.920.2928.830.5326.740.17
2005-01-0124.470.0125.890.2629.210.9127.100.53
2006-01-0124.33-0.1325.00-0.6327.68-0.6225.64-0.93
2007-01-0124.990.5326.500.8728.930.6327.260.69
2008-01-0123.86-0.6024.13-1.5026.62-1.6824.71-1.86
2009-01-0124.42-0.1025.03-0.6027.42-0.8825.54-1.03
2010-01-0124.820.3026.631.0029.511.2128.071.50
2011-01-0124.08-0.4424.31-1.3226.72-1.5824.93-1.64
2012-01-0123.88-0.6424.90-0.7327.09-1.2125.49-1.08
2013-01-0124.00-0.5225.06-0.5728.28-0.0226.16-0.41
2014-01-0124.790.2725.26-0.3728.14-0.1726.06-0.51
2015-01-0124.13-0.3925.990.3629.160.8627.100.53
2016-01-0125.931.4128.212.5829.651.3529.172.60
2017-01-0125.751.2325.61-0.0228.18-0.1226.25-0.32
2018-01-0123.71-0.8124.48-1.1428.03-0.2725.82-0.75
2019-01-0125.100.5726.170.5529.000.6527.080.52
2020-01-0124.550.0225.810.2029.280.9327.090.53
2021-01-0123.89-0.6425.06-0.5527.10-1.2525.58-0.99
\n", - "
" - ], - "text/plain": [ - " Nino12 Nino12anom Nino3 Nino3anom Nino4 Nino4anom Nino34 \\\n", - "datetime \n", - "1982-01-01 24.29 -0.17 25.87 0.24 28.30 0.00 26.72 \n", - "1983-01-01 27.42 2.96 28.92 3.29 29.00 0.70 29.36 \n", - "1984-01-01 24.18 -0.28 24.82 -0.81 27.64 -0.66 25.64 \n", - "1985-01-01 23.59 -0.87 24.51 -1.12 27.71 -0.59 25.43 \n", - "1986-01-01 24.61 0.15 24.73 -0.90 28.11 -0.19 25.79 \n", - "1987-01-01 25.30 0.84 26.69 1.06 29.02 0.72 27.91 \n", - "1988-01-01 24.64 0.18 26.12 0.49 29.13 0.83 27.32 \n", - "1989-01-01 24.09 -0.37 24.15 -1.48 26.54 -1.76 24.53 \n", - "1990-01-01 24.02 -0.44 25.34 -0.29 28.56 0.26 26.55 \n", - "1991-01-01 23.86 -0.60 25.65 0.02 29.00 0.70 27.01 \n", - "1992-01-01 24.83 0.37 27.00 1.37 29.06 0.76 28.41 \n", - "1993-01-01 24.43 -0.03 25.56 -0.07 28.60 0.30 26.69 \n", - "1994-01-01 24.32 -0.14 25.71 0.08 28.47 0.17 26.60 \n", - "1995-01-01 25.33 0.87 26.34 0.71 29.20 0.90 27.55 \n", - "1996-01-01 23.84 -0.62 24.96 -0.67 27.92 -0.38 25.74 \n", - "1997-01-01 23.67 -0.79 24.70 -0.93 28.41 0.11 25.96 \n", - "1998-01-01 28.22 3.76 28.94 3.31 29.01 0.71 29.10 \n", - "1999-01-01 23.73 -0.73 24.41 -1.22 26.59 -1.71 24.90 \n", - "2000-01-01 23.86 -0.60 23.88 -1.75 26.96 -1.34 24.65 \n", - "2001-01-01 23.88 -0.58 24.99 -0.64 27.50 -0.80 25.74 \n", - "2002-01-01 23.64 -0.82 25.09 -0.54 28.81 0.51 26.50 \n", - "2003-01-01 24.38 -0.08 26.38 0.75 29.25 0.95 27.76 \n", - "2004-01-01 24.60 0.14 25.92 0.29 28.83 0.53 26.74 \n", - "2005-01-01 24.47 0.01 25.89 0.26 29.21 0.91 27.10 \n", - "2006-01-01 24.33 -0.13 25.00 -0.63 27.68 -0.62 25.64 \n", - "2007-01-01 24.99 0.53 26.50 0.87 28.93 0.63 27.26 \n", - "2008-01-01 23.86 -0.60 24.13 -1.50 26.62 -1.68 24.71 \n", - "2009-01-01 24.42 -0.10 25.03 -0.60 27.42 -0.88 25.54 \n", - "2010-01-01 24.82 0.30 26.63 1.00 29.51 1.21 28.07 \n", - "2011-01-01 24.08 -0.44 24.31 -1.32 26.72 -1.58 24.93 \n", - "2012-01-01 23.88 -0.64 24.90 -0.73 27.09 -1.21 25.49 \n", - "2013-01-01 24.00 -0.52 25.06 -0.57 28.28 -0.02 26.16 \n", - "2014-01-01 24.79 0.27 25.26 -0.37 28.14 -0.17 26.06 \n", - "2015-01-01 24.13 -0.39 25.99 0.36 29.16 0.86 27.10 \n", - "2016-01-01 25.93 1.41 28.21 2.58 29.65 1.35 29.17 \n", - "2017-01-01 25.75 1.23 25.61 -0.02 28.18 -0.12 26.25 \n", - "2018-01-01 23.71 -0.81 24.48 -1.14 28.03 -0.27 25.82 \n", - "2019-01-01 25.10 0.57 26.17 0.55 29.00 0.65 27.08 \n", - "2020-01-01 24.55 0.02 25.81 0.20 29.28 0.93 27.09 \n", - "2021-01-01 23.89 -0.64 25.06 -0.55 27.10 -1.25 25.58 \n", - "\n", - " Nino34anom \n", - "datetime \n", - "1982-01-01 0.15 \n", - "1983-01-01 2.79 \n", - "1984-01-01 -0.93 \n", - "1985-01-01 -1.14 \n", - "1986-01-01 -0.78 \n", - "1987-01-01 1.34 \n", - "1988-01-01 0.75 \n", - "1989-01-01 -2.04 \n", - "1990-01-01 -0.02 \n", - "1991-01-01 0.44 \n", - "1992-01-01 1.84 \n", - "1993-01-01 0.12 \n", - "1994-01-01 0.03 \n", - "1995-01-01 0.98 \n", - "1996-01-01 -0.83 \n", - "1997-01-01 -0.61 \n", - "1998-01-01 2.53 \n", - "1999-01-01 -1.67 \n", - "2000-01-01 -1.92 \n", - "2001-01-01 -0.83 \n", - "2002-01-01 -0.07 \n", - "2003-01-01 1.19 \n", - "2004-01-01 0.17 \n", - "2005-01-01 0.53 \n", - "2006-01-01 -0.93 \n", - "2007-01-01 0.69 \n", - "2008-01-01 -1.86 \n", - "2009-01-01 -1.03 \n", - "2010-01-01 1.50 \n", - "2011-01-01 -1.64 \n", - "2012-01-01 -1.08 \n", - "2013-01-01 -0.41 \n", - "2014-01-01 -0.51 \n", - "2015-01-01 0.53 \n", - "2016-01-01 2.60 \n", - "2017-01-01 -0.32 \n", - "2018-01-01 -0.75 \n", - "2019-01-01 0.52 \n", - "2020-01-01 0.53 \n", - "2021-01-01 -0.99 " - ] - }, - "execution_count": 41, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# Uses the datetime column\n", "df[df.index.month == 1]" @@ -3296,7 +827,7 @@ }, { "cell_type": "markdown", - "id": "373000f5", + "id": "16d4e0e7", "metadata": {}, "source": [ "You could even assign this month to a new column!" @@ -3304,8 +835,8 @@ }, { "cell_type": "code", - "execution_count": 42, - "id": "2d694ebc", + "execution_count": null, + "id": "fe5d5ee4", "metadata": {}, "outputs": [], "source": [ @@ -3314,7 +845,7 @@ }, { "cell_type": "markdown", - "id": "49100623", + "id": "8750443f", "metadata": {}, "source": [ "Now that it is its own column (`Series`), we can use `groupby` to group by the month, then taking the average, to determine average monthly values over the dataset" @@ -3322,30 +853,17 @@ }, { "cell_type": "code", - "execution_count": 43, - "id": "035b2a37", + "execution_count": null, + "id": "f94c91f9", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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W716NY2Njee0zr333otpmlRWVvL5z3++T3eyDz74IM888wyTJ09m165dHD16lEceeYRdu3Yxf/585s2bF+kXfO3atdx8880sXry4zxUx/Zk/fz633347CxcuZNGiRdx1111UVVWd+4ELIZKOdCcrYsjzIUTiOVN3shduJwJCCJHkJMCFECJJSYALIUSSkgAXQogkJQEuhBBJSgJcCCGSlAQ4dneyq1evjkyvW7cucgfkT3/6U5577rkhbXfLli3MmzePefPmMXfuXF588cV4VFcIIQD5QQdg5LqTnT17dqSHwuPHjzN37lxuuOEG3G552IUQwyctcGK7k+1t7dq1rFu3DoCrrrqKb3zjGyxcuJAZM2ZEOo3y+/3ccccdVFZWUlVVxcaNGwG729hwWPv9fum8XggRVwnVFPzBlh9Q01wT122W5ZbxjYUDd1M+Ut3Jbt68mTvvvJNDhw7xy1/+UlrfQoi4kRa4Y6S6k120aBHV1dVs3bqV73//+/j9/pE7CCHEBSWhmoODaSmPpJHsTra8vJz09HR27tzJggV9ujQQQohzJi3wKPHuTvbgwYORkD906BAfffQRxcXF8a62EOICJQHeSzy7k920aRNz585l3rx5rFy5kieffHJQXcQKIcRgSHeyIoY8H0IkHulOVgghxhgJcCGESFIS4EIIkaQkwIUQIklJgAshRJKSABdCiCQlAY50JyuESE4JdSv9aJHuZIUQyUha4IxOd7L33HMPCxYsoKKigjVr1kTmFxcXs2bNGubPn09lZSU1NXbvjM3Nzdx4443MmTOHyy67jB07dkTqd9ttt7F06VKKi4t54YUXeOihh6isrGTZsmUEg8EReMSEEIkgoZqCJ773Pbp3x7c72ZTyMsZ/61sDljvf3ck+8sgj5ObmYpomS5YsYceOHcyZMweA/Px83n//fZ588knWrVvH008/zZo1a6iqqmL9+vW8+eab3HrrrWzfvh2A/fv3s3HjRnbt2sXll1/OH/7wBx577DFWrlzJyy+/zI033jj0B1AIkbCkBe44393J/va3v2X+/PlUVVVRXV3Nrl27Br2Pa665hqamJlpbWwFYvnw5Ho+HyspKTNNk2bJlAFRWVkbWF0KMPQO2wJVSPwc+DTRorWc789YC/ws46RT7ltb6z8OtzGBayiPpfHUnm5eXx7p169i6dSs5OTncfvvt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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "df.groupby('month').mean().plot();" ] }, { "cell_type": "markdown", - "id": "b04c22fc", + "id": "a0c9481b", "metadata": {}, "source": [ "### Investigating Extreme Values" @@ -3353,7 +871,7 @@ }, { "cell_type": "markdown", - "id": "e3aea3cc", + "id": "fec15b77", "metadata": {}, "source": [ "You can also use ***conditional indexing***, such that you can search where rows meet a certain criteria. In this case, we are interested in where the Nino34 anomaly is greater than 2" @@ -3361,331 +879,17 @@ }, { "cell_type": "code", - "execution_count": 44, - "id": "4e723968", + "execution_count": null, + "id": "098fc88d", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Nino12Nino12anomNino3Nino3anomNino4Nino4anomNino34Nino34anommonth
datetime
1982-11-0124.593.0027.622.6429.230.6028.812.1611
1982-12-0126.133.3428.393.2529.150.6629.212.6412
1983-01-0127.422.9628.923.2929.000.7029.362.791
1983-02-0128.092.0228.922.5528.790.6929.132.412
1997-08-0124.804.1527.842.8529.260.5828.842.028
1997-09-0124.404.0427.842.9929.320.6328.932.219
1997-10-0124.583.7628.173.2529.320.6629.232.5410
1997-11-0125.634.0428.553.5729.490.8629.322.6711
1997-12-0126.924.1328.763.6229.320.8329.262.6912
1998-01-0128.223.7628.943.3129.010.7129.102.531
1998-02-0128.982.9128.932.5628.870.7728.862.142
2015-08-0122.882.2427.332.3429.660.9828.892.078
2015-09-0122.912.5727.482.6329.731.0429.002.289
2015-10-0123.312.5227.582.6629.791.1229.152.4610
2015-11-0123.832.2427.912.9330.301.6729.602.9511
2015-12-0125.012.1927.992.8530.111.6329.392.8212
2016-01-0125.931.4128.212.5829.651.3529.172.601
2016-02-0126.810.6728.361.9929.551.4529.122.402
\n", - "
" - ], - "text/plain": [ - " Nino12 Nino12anom Nino3 Nino3anom Nino4 Nino4anom Nino34 \\\n", - "datetime \n", - "1982-11-01 24.59 3.00 27.62 2.64 29.23 0.60 28.81 \n", - "1982-12-01 26.13 3.34 28.39 3.25 29.15 0.66 29.21 \n", - "1983-01-01 27.42 2.96 28.92 3.29 29.00 0.70 29.36 \n", - "1983-02-01 28.09 2.02 28.92 2.55 28.79 0.69 29.13 \n", - "1997-08-01 24.80 4.15 27.84 2.85 29.26 0.58 28.84 \n", - "1997-09-01 24.40 4.04 27.84 2.99 29.32 0.63 28.93 \n", - "1997-10-01 24.58 3.76 28.17 3.25 29.32 0.66 29.23 \n", - "1997-11-01 25.63 4.04 28.55 3.57 29.49 0.86 29.32 \n", - "1997-12-01 26.92 4.13 28.76 3.62 29.32 0.83 29.26 \n", - "1998-01-01 28.22 3.76 28.94 3.31 29.01 0.71 29.10 \n", - "1998-02-01 28.98 2.91 28.93 2.56 28.87 0.77 28.86 \n", - "2015-08-01 22.88 2.24 27.33 2.34 29.66 0.98 28.89 \n", - "2015-09-01 22.91 2.57 27.48 2.63 29.73 1.04 29.00 \n", - "2015-10-01 23.31 2.52 27.58 2.66 29.79 1.12 29.15 \n", - "2015-11-01 23.83 2.24 27.91 2.93 30.30 1.67 29.60 \n", - "2015-12-01 25.01 2.19 27.99 2.85 30.11 1.63 29.39 \n", - "2016-01-01 25.93 1.41 28.21 2.58 29.65 1.35 29.17 \n", - "2016-02-01 26.81 0.67 28.36 1.99 29.55 1.45 29.12 \n", - "\n", - " Nino34anom month \n", - "datetime \n", - "1982-11-01 2.16 11 \n", - "1982-12-01 2.64 12 \n", - "1983-01-01 2.79 1 \n", - "1983-02-01 2.41 2 \n", - "1997-08-01 2.02 8 \n", - "1997-09-01 2.21 9 \n", - "1997-10-01 2.54 10 \n", - "1997-11-01 2.67 11 \n", - "1997-12-01 2.69 12 \n", - "1998-01-01 2.53 1 \n", - "1998-02-01 2.14 2 \n", - "2015-08-01 2.07 8 \n", - "2015-09-01 2.28 9 \n", - "2015-10-01 2.46 10 \n", - "2015-11-01 2.95 11 \n", - "2015-12-01 2.82 12 \n", - "2016-01-01 2.60 1 \n", - "2016-02-01 2.40 2 " - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df[df.Nino34anom > 2]" ] }, { "cell_type": "markdown", - "id": "2bc0275e", + "id": "f26bc439", "metadata": {}, "source": [ "You can also sort columns based on the values!" @@ -3693,236 +897,17 @@ }, { "cell_type": "code", - "execution_count": 45, - "id": "a3cd6935", + "execution_count": null, + "id": "8051c4f6", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Nino12Nino12anomNino3Nino3anomNino4Nino4anomNino34Nino34anommonth
datetime
1988-11-0120.55-1.0423.03-1.9526.76-1.8724.27-2.3811
1988-12-0121.80-0.9923.07-2.0726.75-1.7424.33-2.2412
1988-10-0119.50-1.3223.17-1.7527.06-1.6024.62-2.0710
1989-01-0124.09-0.3724.15-1.4826.54-1.7624.53-2.041
2000-01-0123.86-0.6023.88-1.7526.96-1.3424.65-1.921
..............................
1997-11-0125.634.0428.553.5729.490.8629.322.6711
1997-12-0126.924.1328.763.6229.320.8329.262.6912
1983-01-0127.422.9628.923.2929.000.7029.362.791
2015-12-0125.012.1927.992.8530.111.6329.392.8212
2015-11-0123.832.2427.912.9330.301.6729.602.9511
\n", - "

472 rows × 9 columns

\n", - "
" - ], - "text/plain": [ - " Nino12 Nino12anom Nino3 Nino3anom Nino4 Nino4anom Nino34 \\\n", - "datetime \n", - "1988-11-01 20.55 -1.04 23.03 -1.95 26.76 -1.87 24.27 \n", - "1988-12-01 21.80 -0.99 23.07 -2.07 26.75 -1.74 24.33 \n", - "1988-10-01 19.50 -1.32 23.17 -1.75 27.06 -1.60 24.62 \n", - "1989-01-01 24.09 -0.37 24.15 -1.48 26.54 -1.76 24.53 \n", - "2000-01-01 23.86 -0.60 23.88 -1.75 26.96 -1.34 24.65 \n", - "... ... ... ... ... ... ... ... \n", - "1997-11-01 25.63 4.04 28.55 3.57 29.49 0.86 29.32 \n", - "1997-12-01 26.92 4.13 28.76 3.62 29.32 0.83 29.26 \n", - "1983-01-01 27.42 2.96 28.92 3.29 29.00 0.70 29.36 \n", - "2015-12-01 25.01 2.19 27.99 2.85 30.11 1.63 29.39 \n", - "2015-11-01 23.83 2.24 27.91 2.93 30.30 1.67 29.60 \n", - "\n", - " Nino34anom month \n", - "datetime \n", - "1988-11-01 -2.38 11 \n", - "1988-12-01 -2.24 12 \n", - "1988-10-01 -2.07 10 \n", - "1989-01-01 -2.04 1 \n", - "2000-01-01 -1.92 1 \n", - "... ... ... \n", - "1997-11-01 2.67 11 \n", - "1997-12-01 2.69 12 \n", - "1983-01-01 2.79 1 \n", - "2015-12-01 2.82 12 \n", - "2015-11-01 2.95 11 \n", - "\n", - "[472 rows x 9 columns]" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.sort_values('Nino34anom')" ] }, { "cell_type": "markdown", - "id": "9af53b83", + "id": "a293de79", "metadata": {}, "source": [ "Let's change the way that is ordered..." @@ -3930,236 +915,17 @@ }, { "cell_type": "code", - "execution_count": 46, - "id": "d89c47e8", + "execution_count": null, + "id": "be7ff8ce", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Nino12Nino12anomNino3Nino3anomNino4Nino4anomNino34Nino34anommonth
datetime
2015-11-0123.832.2427.912.9330.301.6729.602.9511
2015-12-0125.012.1927.992.8530.111.6329.392.8212
1983-01-0127.422.9628.923.2929.000.7029.362.791
1997-12-0126.924.1328.763.6229.320.8329.262.6912
1997-11-0125.634.0428.553.5729.490.8629.322.6711
..............................
2000-01-0123.86-0.6023.88-1.7526.96-1.3424.65-1.921
1989-01-0124.09-0.3724.15-1.4826.54-1.7624.53-2.041
1988-10-0119.50-1.3223.17-1.7527.06-1.6024.62-2.0710
1988-12-0121.80-0.9923.07-2.0726.75-1.7424.33-2.2412
1988-11-0120.55-1.0423.03-1.9526.76-1.8724.27-2.3811
\n", - "

472 rows × 9 columns

\n", - "
" - ], - "text/plain": [ - " Nino12 Nino12anom Nino3 Nino3anom Nino4 Nino4anom Nino34 \\\n", - "datetime \n", - "2015-11-01 23.83 2.24 27.91 2.93 30.30 1.67 29.60 \n", - "2015-12-01 25.01 2.19 27.99 2.85 30.11 1.63 29.39 \n", - "1983-01-01 27.42 2.96 28.92 3.29 29.00 0.70 29.36 \n", - "1997-12-01 26.92 4.13 28.76 3.62 29.32 0.83 29.26 \n", - "1997-11-01 25.63 4.04 28.55 3.57 29.49 0.86 29.32 \n", - "... ... ... ... ... ... ... ... \n", - "2000-01-01 23.86 -0.60 23.88 -1.75 26.96 -1.34 24.65 \n", - "1989-01-01 24.09 -0.37 24.15 -1.48 26.54 -1.76 24.53 \n", - "1988-10-01 19.50 -1.32 23.17 -1.75 27.06 -1.60 24.62 \n", - "1988-12-01 21.80 -0.99 23.07 -2.07 26.75 -1.74 24.33 \n", - "1988-11-01 20.55 -1.04 23.03 -1.95 26.76 -1.87 24.27 \n", - "\n", - " Nino34anom month \n", - "datetime \n", - "2015-11-01 2.95 11 \n", - "2015-12-01 2.82 12 \n", - "1983-01-01 2.79 1 \n", - "1997-12-01 2.69 12 \n", - "1997-11-01 2.67 11 \n", - "... ... ... \n", - "2000-01-01 -1.92 1 \n", - "1989-01-01 -2.04 1 \n", - "1988-10-01 -2.07 10 \n", - "1988-12-01 -2.24 12 \n", - "1988-11-01 -2.38 11 \n", - "\n", - "[472 rows x 9 columns]" - ] - }, - "execution_count": 46, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.sort_values('Nino34anom', ascending=False)" ] }, { "cell_type": "markdown", - "id": "089d75db", + "id": "5504a0da", "metadata": {}, "source": [ "### Resampling\n", @@ -4168,53 +934,27 @@ }, { "cell_type": "code", - "execution_count": 47, - "id": "1a5c0bf6", + "execution_count": null, + "id": "597cfeac", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "df.Nino34.plot();" ] }, { "cell_type": "code", - "execution_count": 48, - "id": "376714eb", + "execution_count": null, + "id": "9e3ee506", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX4AAAEGCAYAAABiq/5QAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAAsTAAALEwEAmpwYAABPaklEQVR4nO29eZyb51nv/b0kjaSRNPvqGXs8Y8d24qxOHCd2mjSELmmgpJRCU2hpCy95C4XTQoG3hXM4cHjhQOG05xwoL5RunLYk3dKSQpp0hTROY8dZ3HhJ4mXG9uyj2Tft9/vH8zwaeayZ0fJoGen+fj7+WCM90tx+LF26nuv+Xb9LlFJoNBqNpnpwlHoBGo1GoykuOvBrNBpNlaEDv0aj0VQZOvBrNBpNlaEDv0aj0VQZrlIvIB2tra2qt7e31MvQaDSaTcNzzz0XVEq1ZXJsWQb+3t5ejh07VuplaDQazaZBRC5keqwu9Wg0Gk2VoQO/RqPRVBk68Gs0Gk2VoQO/RqPRVBk68Gs0Gk2VoQO/RqPRVBk68Gs0Gk2VoQO/RqOpSg6fDXJuYqHUyygJOvBrNJqq5INfepG/+d6ZUi+jJOjAr9Foqo54QjG5EGZ0LlTqpZQEHfg1Gk3VMbUYIaFgfC5c6qWUBB34NRpN1RFcMAL++LwO/BqNRlMVWIF/IRxjIRwr8WqKjw78Go2m6phciCRvj1dhnX/DwC8i20TkByJyWkROisgHzPtvEpFnRORFETkmIgfWeP6AiLxkHWf3P0Cj0Wiyxcr4oTrLPZn48ceADymlnheROuA5EfkO8FHgT5RS3xKR+8yf717jNX5CKRW0ZcUajUaTJxMpgX+sCjP+DQO/UmoEGDFvz4vIaaAbUEC9eVgDMFyoRWo0Go2dBOcj1HlczIdjVansyWoCl4j0AvuAI8AHgSdE5K8xSkaH1niaAr4tIgr4B6XUJ9d47QeBBwF6enqyWZZGo9FkRXAhTF+bn1fH5hmfr76MP+PNXREJAF8DPqiUmgN+HfhtpdQ24LeBT6/x1DuUUjcDbwLeLyJ3pTtIKfVJpdR+pdT+traMxkZqNBpNTkwuhmkNeGiv8zJWhRl/RoFfRGowgv4XlVKPmHe/G7BufwVIu7mrlBo2/x4Hvr7WcRqNRlMsgvMRWvxuOuo9VVnjz0TVIxjZ/Gml1MdSHhoGXmvevge4wvRCRPzmhjAi4gfeAJzId9EajUaTK0opI+Ov89Be72VCq3rScgfwLuAlEXnRvO8PgF8D/peIuIAQZn1eRLqATyml7gM6gK8b3x24gH9WSj1u679Ao9FosmB2OUo0rmgNeAhHE/z73Hipl1R0MlH1PAXIGg/fkub4YeA+8/Z54MZ8FqjRaDR2Ymn4WwNuovEEi5E4C+EYAU9WWpdNje7c1Wg0VUXQ7NptC3joqPcA1de9qwO/RqOpKqyMvyXgoaPOC1B1yh4d+HMkFk/w5WOXiCdUqZei0WiyIDi/UupptzL+KtPy68CfI0+fm+T3v/pjnh2YKvVSNBpNFgQXIjgdQpPPTXu9kfFXW/euDvw5MjprZAhzy9ESr0Sj0WRDcCFMs9+NwyHUeVzU1jirTsuvA3+OWG+UxUj1eXlrNJuZ4EKE1oBR4hER2us9jFWZll8H/hyxrFwXw/ESr0Sj0WRDcCFMa8Cd/LmjzqtVPZrMsDaDFqtweo9Gs5kxAr8n+XN7vafqPPl14M8RS/6lA7+9jM+H+PRT/Sil1VIa+1FKXZHxG0Ztoap6z+nAnyOWv8diRJd67OTffjzCn/7rKQanl0u9FE0FshiJE4omLsv4O+o9LJndu9WCDvw5oJTSpZ4CMbNkqKQmFyMbHKnRZM9k0q4hNfCbks4qKvfowJ8D00uGyRPojN9uZk157ORC9XwINcVjpWs3pdRjNnFVk6RTB/4cSO3y0xm/vcwsGZn+5ILO+DX2MzFvvK8u29ytq74mLh34c8B6g9Q4parqgsVgxsz4g4vV8yHUFA8r42+ru7zGD9Vl26ADfw5Yl4TbW/ws6QYuW0nW+HXGrykAVuBv9q+UegIeFz63s6qM2nTgzwFrE6i3xa8buGxmTtf4NQVkciFCk6+GGudK6BMR2uuqawSjDvw5MDEfps7rojXg1qUem7FKPVrVoykEwYUwLSn1fYv2eq9W9WjWZ2wuRHudB7/HxZIO/LaRSKjk5m5Ql3o0BWB185ZFR3112TbowJ8D4/Nh2uu8+D0uFiNxEtqT3xYWIjGsU6lLPZpCkGrQlopR6glXTfeuDvw5MD4foqPeg9/tBGA5quv8djBrbux21nuZWozoL1SN7QTnw2kDf0e9h+Vo9XTv6sCfJUopxubCtNcbGT9oLb9dWM1bO9r8xBIq+bNGYwehaJz5cOwyKaeF1b1bLcoeHfizZG45RiSWMGv8RsZfLVlCobGknDvbAgBMai2/xkYswUCL/8oav/VlUC11fh34s8Rq8miv9+J3Gxn/krZtsIWZZeODubPND+gNXo29rMzaXTvjrxZlj6vUC9hsWJeC7XWeZA1aZ/z2kMz4282MXwd+jY1YzVut65Z6dMZfMsKxRKmXsCbJjL/Og0/X+G1lpcavSz0a+0kG/jRyzoDHhb+KunfLMuMv5wzauhRsr/eSUIZnvHbotIfZ5SjeGged9V5EdKlHYy/W+yldqQesJi6d8QMgIttE5AciclpETorIB8z7bxKRZ0TkRRE5JiIH1nj+vSLyioicFZEPZ7Kocs6gx+fC+N1OI0PQGb+tzCxFaKx143QIzT631vJrbCW4ECbgceGtcaZ9vL3OUzUOnZmUemLAh5RS1wC3A+8Xkb3AR4E/UUrdBPyR+fNliIgT+ATwJmAv8A7zueuyFI6XbSPF2HyIdrMe6HPrwG8nM0tRGn01gOGXrmv8GjsxmreuLPNYdNR7GdMZv4FSakQp9bx5ex44DXQDCqg3D2sAhtM8/QBwVil1XikVAR4G7t/od0YTibIdvTcxF6bd3ByyGri0UZs9zCxHaag1A7/fo2v8GltZq3nLwsr4yzXptJOsNndFpBfYBxwBPgj8lYhcAv4a+Eiap3QDl1J+HjTv25BnB6ayWVrRGE/J+F1OBx6Xg0VtzWwLszrj1xQQw6dn7cDfUe9l2WzyqnQyDvwiEgC+BnxQKTUH/Drw20qpbcBvA59O97Q096X9OhWRB829gmMCPDswnenSikayazdFDhbwuHSpxyZmliPJjL814EmqMDQaO5hcjFw2cnE11gjGamjiyijwi0gNRtD/olLqEfPudwPW7a9glHVWMwhsS/l5K+lLQiilPqmU2q+U2h/wuMoy418Ix1iOxpMTewDDqE0HfluYXY7S6DM+mK0BN3OhGOGYLqNp8icWTzC9lN6gzaKaRjBmouoRjGz+tFLqYykPDQOvNW/fA5xJ8/RngV0i0icibuAB4NGNfqfP4+Ls+AJTZebJnpRymm8QAJ/byYKu8edNKBonFE2s1PjND2i5vQc0m5OpxQhKpW/esrASumrY4M0k478DeBdwjyndfFFE7gN+DfgfInIc+HPgQQAR6RKRxwCUUjHgN4EnMDaFv6yUOrnRL7Q8cI6VWdZvdfWtLvXo8Yv5YzVvJWv8pp+KrvNr7GDCmrW7bqmneozaNmzgUko9RfpaPcAtaY4fBu5L+fkx4LFsFuWrcRF3Onh2YIo3XNuZzVMLykRK85aF3+NKDg/R5I5l19BYa3wwrYxf1/k1drBR8xakdu/qjL8kiMCN2xrKboPXqv21X1bjd5Z1p/FmwfryXNnc1Rm/xj6sZsB0YxdT6aiSEYxlGfgB9vc2c2JotqzKKGNzIbw1Duo8KxdKfrdLu3PawBWlHvMDqrX8GjtYz6cnlfZ6j1b1lJIDvc3EEooXL82UeilJxufDdNR7Mfa7Dfwel874bcAasm5l/H63E4/LoTN+jS0EFyJ4XA4CnvWr2x313qqo8Zdt4L95exMi8Gx/+ZR7xudDl23sglHqWYqUr8XEZsEau2hl/CJiavl14Nfkj9W1m5q0paO9zsP4fKjiP89lG/gbamvY01HHsQvlo+wZnwtfJuUEI+OPJ1RZW0lvBmaWIzgdcllG1hJw61KPxhYmFsLrSjktOuq9hKIJ5kKVfRVftoEf4NbeZp6/ME0sXh5BdXw+fNnGLpCcwqXLPfkxs2T49KRmZC1+bdugsYfJhQitaUYursZS7FV6nb+8A39fM4uROKdH5ku9FBbDMRbCsbQZPxiOoprcmV2O0mjW9y1aAh5tzayxhY18eiysUm6lK3vKO/D3NgFwtAwauVa6di9/8wT0wHVbmF2O0uC7PPBbNf5Kr7dqCksioZhcjNBat3HGXy0jGMs68G9pqGVrU21ZdPBal34d9Zdn/ElP/jKSnW5GZpauzPhbA24i8URVuCVqCsfMcpR4QmWV8Ve6sqesAz8Ydf5nB6ZKnvWtjFxcrerRw1jsYGY5kjRos2gp8yYupRTRMtl/0qzNioZ/48Dv97gIeFwVP4JxUwT+4EKEgcmlkq4jnU8PrPgK6WEs+WFt7qbS4jebuMq0zv/lY5c4+N+/Tyiq/+/LmeC81bW7cakHrCau8nzP2cUmCPxGnf/Z/tKWeybmw7hdjiuCk1+XevImnlDMh2JXBn7zg1quWv7jg7MEF8IcKfF7U7M+QdPhtS2DjB+go86ra/yl5qr2AE2+mpL784/PGwNYVjeABHSpJ2/mVtk1WLSWuW3DkDke9MlXJ0q8Es16WBl/JqUeMDN+reopLSLCLdubSx74x+au7NoF8CVLPTrw58rMGoG/yVfeNf6hGR34NwPBhTAuh1xxRbkWhm1DZXfvln3gBzjQ18TA5FJJN1wsn57VeFxOapzCojZqyxnLmdOyZLawSmvlWONXSjE0vYzP7eTM+AIjs8ulXpJmDYILYVoCbhyO9e0aLNrrPIRjCeaWKzeZ2xSB/9beZgCOldCmeXyNjB/0+MV8sTL++jQZWUvAnazRlhNTixGWo3F+5sYuAH74arDEK9KsRXAhkhQKZIKV4FWysmfDQSzlwLVdDXhrjMEs912/pei/PxSNMxeKXTaAJRW/u7QOnS9emuHE0CwL4RgLIaPDeD4UYz4UNe4Lx3A5hH/85f0b+pGXgrVq/ACt/vLs3rXKPHfvaecHr4zzH2cm+IVbt23wLE0pmMzQp8ciVcu/q6OuUMsqKZsi8LtdDvZtaypZnT85gGXNjN9ZMsuGWDzBuz51JNnk5BBjw7nOW0Od19AkN/rcPPnqBF945iIfeN2ukqxzPVamb6XP+M+OLxR7SRtibexubarlzl1tfOfUGPGEwplhOUFTPIILEXa2BzI+vhq6dzdF4AdD1vm3PzjLQji2oae23ViXfGtm/B5XyeScJ4bnmA/H+Mufu54339hFbY0zrfXsez57lC8cucCv370Tt6u8KnxW4E+3+dYScHOkv/xKPVbGv7Wplrt2t/HV5wZ5aWiWm7Y1lnZhmstQSjGxEM5YygkrTZqVrOwprwiwDrf2NZNQ8PyF4tf5xzbK+EtY6jnaPwnAT1zdjs/tWtNv/L139DExH+axl0aKubyMmFmOUOdx4XJe+XZs8XuYXoqUjUOrxeD0Mn63k4baGl5zVSsiWt1TjsyHY0RiiYylnGDYsNR5XBWd8W+awL+vpwmHUJJyj5Xxp1P1QGlLPUfOT7Gj1X+Fa+hq7ryqlR1tfj57uL/sZGqzS9G0G7sArXUelIKpMhtoPzSzTHdTLSJCs9/N9d0NOvCXIdl27VoYWn4d+EtOwOPi2q6GEgX+MDVOoSnN5iOULuOPJxRHB6a4bUfzhsc6HMJ7D/VyfHCW5y/OFH5xWTC7HE27sQskPdTLTcs/NL1Md2Nt8ue7drXxwqUZ5kLREq5Ks5pJUxGWTcYPlT+CcdMEfoD9vU28cHGGSJGnXY3NhWhbZ2yb3+MqyVD4l0fnmA/FONC3ceAHeOvNW6nzuvjc0wOFXViWzKwT+JND18st8JsZv8Vdu9uIJxRPn9WyznIi265dC2sEY6WyqQL/gd5mwrEEJ4Zni/p7J+bDa27sgqXjL36p58h54+rntr6WjI73e1y8ff82vvXSCKOz5fOmnlmKXNG8ZZF06Cwj24aFcIzZ5Shbm3zJ+/b1NBLwuHjyjA785UTSmTMDL/5UrIy/GGXRp88F+ejjLxf896SyqQL/frORq9iGbcas3bUzBr/bSSSeKPqVyNH+KbY21dKVUnLYiHcf6iWhFJ9/ZqBwC8uSdENYLFrNxptyMmqzpJyppZ4ap4ODO1t48tWJsttDqWYmFiKIQLMv2xq/l0gswexy4Ut3n/phP3/37+eK6vK6qQJ/W52HvlY/zxa5g3dsPnSFD38qyfGLRSz3KGXW9zPM9i22Nft43TUd/PORi2VhJ6yUSmvJbFFf68LlkLJq4hqaMSzCU0s9YJR7BqeX6Q8ulmJZmjQEF8I0+dxpFWPrUawRjNF4giPnDWXe4HTxrOc3VeAHuLmnieODM0X7feFYnJmlKB3rqGasvoJibvCeHV9gajHCbRnW91N5zx29TC9FefTF4QKsLDuWInFiCZW2eQsMk76WQHkNXU82b6260nrtrjZAyzrLicmFMK1ZKnqgeE1cPx6cSfp8XZwqo8AvIttE5AciclpETorIB8z7vyQiL5p/BkTkxTWePyAiL5nHHct3wduaa5mYDxdt8tHEGpO3UvGVYBjLM2a5KxNFz2oO7mjh6s46PlMG0s61nDlTafF7yqrGPzizjNvpuGLDsKfFx/YWHz/Udf6yIbgQyXpjF6CjvjgjGA+fnUzevljEYVOZZPwx4ENKqWuA24H3i8hepdTblVI3KaVuAr4GPLLOa/yEeez+fBdsfRNPFKmrbqV5a/3NXSjuMJaj/VN01nvpafZtfPAqRIT33tHLy6PzJR8iYjlzNqyxuQumUVsZZfyD08t0NXrTuj3etauNH52fLPp+jyY9wYVwToHf+rwXWtlz+GyQ67rr8bmdXCinjF8pNaKUet68PQ+cBrqtx8XQOP4C8FChFpnKyjdxcVQpE0m7hvU2d4s7jEUpxZHzkxzoa15TYroR99/UTZOvhs8e7rd5ddkxu7Rxxt8aKK+Mf2h6+Yr6vsVdu9tYisQ5dkFP5SoHgvO5Bf5at5M6r6ugIxiXIjFeuDjDHTtb6Wn2camcAn8qItIL7AOOpNx9JzCmlDqzxtMU8G0ReU5EHlzntR8UkWMicmxiYu0aqfVNXKzmiuSQ9XUz/uKWeozZBOGcyjwW3hon7zjQw3dOjRX1Dbcaq9Sz3pCMFr+b4Hz5ZPxDM5c3b6VycGcLLofwpLZpLjnLkTiLkXjWXbsW1kCWQvHswDSReIJDV7WyrdlXXjV+CxEJYJR0PqiUmkt56B2sn+3foZS6GXgTRpnornQHKaU+qZTar5Ta39bWtuaLrRgoFSfjH5sL4XQILf613zzFHr9o+fPksrGbyrsObkdE+PwzF+xYVk7MZlLjD3hYjsZL0iS3mlA0zsR8mO7G9CW2gMfFzdub+OEZvcFbaiwNfzYGbal0FHgE49Nng9Q4hVt7m+gxA3+x9twyCvwiUoMR9L+olHok5X4X8FbgS2s9Vyk1bP49DnwdOJDPglv8HpwOKeglWCrjc4az33rTe3xFHrh+5PwULX43O9syt5pNx5aGWu69rpOHj14sWVBdsWRe+4vVUmWUg7JnxGx8W6vUA/Da3W2cHJ4r2j6UJj25Nm9ZtBd46Prhc0H29TThc7voafYRiiaYKJJsORNVjwCfBk4rpT626uHXAS8rpQbXeK5fROqs28AbgBP5LNjpENoCnqLV+Mfnw+vW9yE14y9OqedI/1Re9f1UfuWOXuZCMb72/NC6x43Nhfje6THb1VQzyxHcLgfemrXfilaNNlgGWv50zVurucuUdT51Vmf9pcQSBORS4wfTqK1A3bszSxFODs9xx85WgKRIo1hl10wy/juAdwH3pMg37zMfe4BVZR4R6RKRx8wfO4CnROQ4cBT4N6XU4/kuuqPew1jRVD1rj1y08NY4cEhxSj2D00sMzSznXeaxuLmniRu2NvC5w/0kEitv8FA0zlNngvz5Y6e5938+yW1//j1+9Z+O8c3j9mr/Z5eiNNbWrPsl1lJGGb/VvLV1nYz/2q56mv1uXecvMcmMP9dST52XSLww3bs/OjeJUnDHVUYDZk+LEfgvFEnSueFEE6XUU0DaT6VS6j1p7hsG7jNvnwduzG+JV9Je7y3aN+PEfJibtzete4yIFM2h82hSv59dx+5aiAjvOdTL73z5OF86donlSJwnz0zwzPlJQtEEbqeD/b1NfPhNV/M33zvD8UszvPXmrbb8bmDdrl2LpFFbGSh7hqaXcQh0Nqy92e9wCK+5qpUfngmSSKg1y4RKKR49Psy/vDjMR992Q84BqlgopZgPx6j3rv//VS5YBm3N6+zPrYclHR+eCdGYpeXDRhw+F8TvdnKjObinu7EWkeI1cW2aCVyptNd5OFYEe+ZoPMHkYmTDjB+K59B55PwUDbU17LFxFuhP3bCFP3/sZT7yyEsA9LX6efv+bdy1u43bd7Qk+xS+f3qcl4bsNchbz5LZwtpYLwct/+DMMh31Xmo2sAC4a3cbjx4f5vToHNd2NVzxeHAhzH/5xgm+dWIUgM8e7uf33nh1QdZsF0+cHOODX3qBw//PPWU5u3k1k4sR6rwuvDXOnJ5/zRbjM/bipRn2dtXbuTSePjvJbTtaku8jb42TznqvDvzr0VHvZXopSjgWx+PK7T81EyYykHJa+DzOotT4j/RPcmtv87qbzdnicTn5u1+6mbPjC9y5y5CWpeO67gb++egFYvFE1t4nazGzHF23Xg7GhyLgcZVHqWd6bSlnKnftMmq3T74avCLwP/bSCP/5GydYCMX4/Xv38MLFGb7wzEV+4+6rkl+y5cjLo3OEogleHVvg4CYI/NmOXFxNX6ufjnoPT58L8ou39di2ruGZZc4HF694zW1F1PJvOq8eWGniKrRqwpJydWywuQvGBm+hSz1jcyEGJpdsq++ncqCvmV+8rWfNoA9w/dZ6QtEE5ybsMyGbXYpsmPGDUecvi1LPzPK69X2L9novV3fWXebbM70Y4bceeoHf+OLzdDfW8s3feg2/cfdVvO+1O5ldjvKVY5cKufS8say8ByY3hwldrs1bFiLCoZ2tPHN+0tYN3sPmzIY7rmq97P6eImr5N2Xgb68vThPXuKkcyiTj97sLX+o5koc/jx1c321krnaWe2aWo2satKXS4i+9UVs8oRidDa0r5Uzlrt1tHLswxVIkxndOjfH6jz/J4ydG+NDrd/PIbxxiT6dRSrhlexO3bG/i04f7y262cCqWlHVgk7iPBhfCOUs5LQ7uaCG4EOHM+IJNq4Knz03S4ndfUa7tafYxNhcuimvupgz8llPmeIElnWMZGLRZ+D1OFgpc6jnaP0nA42LvFnvrjZnS1xrA53ZywqbAH4klWIrEN9zcBWODt9RyzrG5ELGEWrN5azV37WojGle881NH+LX/c4y2Og//8v7X8Fs/ueuKPYJfu3MHl6aWefzkaCGWbguWhHqz2E4HFyK0+PMrSR3caYgofnRucoMjM0MpxeGzQQ7ubLmiXLvdVPYUw555cwb+Ivn1TMyFcAjrdu1aFGNz98j5KW7Z3mRbfT1bnA7h2q562zL+TLp2LVoD7uT81FIxaGn4M8z49/c2UVvj5PjgLP/pJ3fxL++/Y81Nwtfv7aCv1c8/Pnm+5I6pazGyiUo91hCVfJVS25p9bG2qtS3wn5tYYHw+fEWZx/pdUBxJ56YM/E0+Ny6HFFzLPz4fpiXgySjQGuMXCxf4JxfCnBlfKFmZx+LargZODc8RT+QfnGaXTWfODKRyLX4PU4uRy3oNik1yAEuGE8+8NU4+995b+dffeg2/8/rduF1rv4+cDuFXX9PH8cHZpGS3nFiOxJldjlLjFAYml0r6/5AJU9aQ9TxLPWCUe57pn7Tl32zZMFuNW6lYTVzFqPNvysDvcAjtdYXv3s2kecvC73YWdHP32QFrvm5pA//13Q0sR+Ocm8i/5rli15DZ5m48oZKmbqUgk67d1dy2o4VrMizNve2WrTT73fzjD8/ntL5CMmp+1m7a1kgklmB4drnEK1qffJu3Ujm4s4WZpSinR+c2PngDDp8NsrWpNtmwlUqL343P7dSBfz3a670F9+sZnw8nmzg2wu9xEYombMmE0/HM+Sm8NQ6u724syOtnyvVbzQ3ewfzLPTMZWDJbWB/gUo5gHJpZpsXvptZdGAmxt8bJLx/czndPj3PWxs1EOxgxA/3tZuPgQLB0jq6ZMGFz4If86/zxhOKZ85O8Jk2ZBwwVUbHsmTdt4Dec8wqb8Y/Prz9kPRV/gY3ajvZPcXNP07rlgmKwsy1AbY2TE8M2BP4MLJktLNuGUjZxDa7jw28X77p9Ox6Xg0+VWdZvSTkPmoG/v8zr/FbXbi5jF1ezpaGWvlZ/3oH/xNAsc6EYh9YI/EDR7Jk3ceD3FlTOGYsnCC5kEfgLaM08a15mZjtYvRA4HcLernpblD3Jzd11nDktWsvAtmE9H367aAl4eNstW3nk+aGiWY9nglXquXFbI7U1zrKXdFob0XbZYNy+o4Wj/VN5yW0PnzP0+4d2rv053l4ke+ZNHfhnl6MF07xOLkZQaqVnYCMKOYzl2IUplDKarMqB67sbOGnDBu/sUgQRqPNu3K1qKatKpeVXSjFchMAP8H/duYNoIsHnf1S6OQmrGZ0NUe914fe42N7iK/vAf7R/iqs762zrhD60s4X5cIyTw7nX+Q+fDXJ1Z926X0Y9LaY9c4GFK5s28LeZmXih6vzjyVm7WZZ6CpDxH+mfwu10sK+n0fbXzoXruhtYisTpD+ZXh55ZNgzaMrGfaPS5cUjpavyTixFC0UTBSz1gWAW8YW8Hn3/mQlkMnwEjg97SYPzb+1r9ZV3qCUXjPDswxaE0yplcsfY2ns6x3BOKxjk2ML3hmrYVSdmzaQO/tek6VqDLYUsxlHnGX7ga/5Hzk9y4rSFnsym7sauDd2Yps65dMEpMzX43wRJp+XNR9OTDg3ftYGYpylefSzvqouiMzYWSjqS9rX4uTi6VbZfx8xemCccSSctjO2ir87CrPcCPzucW+DNdU7EknZs48Be2iSsbnx4o3DCWhXCME8PlUd+32Nnmx1vj4KXB/ORtVsafKS1+T8ky/qGZ7Jq38uWW7c3c3NPIp37Yv2FJ7filGT76+MsFPTcjsyE6zSSor8VPLKGS56TcOHwuiNMhtlmXWxza2cKxgSkisey/8Kw1bVSuLZY98+YN/EnbhgKVeuZDiGS+OeRL1vjtzfifuzBNPKFK3riVisvpYO+W/Dd4Z5ejGTVvWbQESufXY2X8WzO0a7CDB+/aycWpJZ5IY+MQjSd49Pgwb/27w9z/icP83b+f41Gbh+Sk/q7gQviyjB/K17rh8NlJbtrWmEzG7OLgzhaWInF+PDiT05pu3NpA3QazDIplz7xpA3+jrwa301GwUs/4fJhmn3tD33WLQIFKPS9cnEbEmJRVTlzX3cDJ4dm8uhlnlyIZl3rAULyUyrZhaGaZOo+L+tri2Sa/fm8HvS0+/iHFxmFyIczffO8Mr/nL7/OfHnqBqcUI//XNe2n01fDqWGG0/+PzYZSCLcnAb3z5leMG7+xylB8PzqS1RMiX2/paEMlezz8Xym5NxbBn3rSBX0SSMzELwfhcKLmBnAk+d2Ey/otTS2yp95adT/t13Q0sRuKcz+PDP5PBEJZUWvzupD672FgafjvmHGeK0yH86p07OH5phoeOXuJ3v3Kcg3/xff7Hd15lT2c9n33PrXz/Q3fz3jv62NNRx6tj8wVZx6jZvNVhBv62gIeAx8VAkcYEZsOR85MkFNyxjmQyV5r8bq7prM96g/fI+SljTRkG/u3NvoL79ZRXNMkSQ8tfuIw/065dWFH12O3QOTi9zNam4pUXMsXa4D0xNMtV7YGsn59IKGP6VhYZf2vAzXw4RigaL/pG9+D0UtE2dlN5281b+fh3XuUPvv4SPreTt+/fxrsP9V5xzvd01vH154dQStn+5WRp4q2MX0TobfWVZann8NkgtTVO9hXoCvngzhY+/8yFrN6Dh88G8dZkrsrrafYxPh9mORIvWJf4ps34gYL69QxOL9OVxQfd4RB8bidLNmf8Q9OZDf4oNrvaA3hcjpyVPfOhGEpBfZalHlgx4ComQzOF79pNR63bycfffhN//Oa9/OgjP8mfvuW6tF+0uzvqmA/HGJ61//Ngde1uqV/59/e2+MvSpfPwuUkO9DUXrMP94I4WIrEEL1ycyXxNZ4Pc2tuc8bTAniLYM2/qwN9RIL+e2aUoU4sRdpibWJnic7tsrfFH4wlGZksTcDbC5XRwTR4bvCuWzFls7paoiWsuFGU+FCtJxg/w2t1tvOeOvnUVUNZQl1dH7S/3jM6G8NY4Ltvf6Gv1c2lqKSeFS6EYmwtxdnzBVhnnag7saMYh8COzC3cjzo7Pc2Z8Ias9h2Jo+Td14G+v9zAfjtne5GI1p/RmGfgDNs/dHZ0NkVCUZcYPKx28uWzwzpiWzFmVesw9l2CRbRuGsvThLwW7243A/0oB6vwjc0bzVmoJqbfFT0LBpSIMDckUa6ShnY1bq6n31nB9d0NGev5YPMGHvvJjGn01/NzNWzP+HcXQ8m/qwF8oSafVkdrXml1t3W5PfutDVY41fjAC/0I4ltMlfzbOnBatfsuhs7gZf7Gbt3KhwVdDZ723YBl/56r9LispKidlz+GzkzT5ago+oe72nS28eGlmw4TzH548z/FLM/zp/ddlJRQphj3z5g78ydm79tY1+4NLOIR1B4+nw++2d+B6UjteppnmdXl08M5kMX3LwnLoLHYTV7Gbt3JlT2ddQTL+0dlQcmPXYkeZafmVUjx9Lsihna0ZWYDkw6GdrUTjimMD02se8/LoHP/zu6/yU9dv4c03dmX1+pY988UCKns2eeA3u3dtlvj1BxfpbqrNeDPGwu9xshSxr9QzOL2MCEmPlHJjV0cAt8uRU51/dsnI2rPZ3PW5nXhrHEXX8g/NLON2OZJXHOXKns46zowv2DoTIpFQjM2FklJOiya/m4bamrLZ4D0fXGRkNlQQ/f5q9m9vwuWQNcs90XiCD335OA21NfzpW67L6Xf0FNieeVMH/vYCDV0fCC7S15q9RNFnc6lncHqZznpvyT3416LG3ODNJeOfzcKL30JEaPEXf+j60LThylnoTDJfdnfUEYklbA3GwcUwsYS6IuMHo9xTLgNZnjbr+4Xc2LXwe1zcuK1xzUauv/3+WU4Oz/FnP3s9zRnM605HT4HtmcszomRIfa0Lj8tha6lHKUV/cJG+NKPRNiJgc6lncHqpbMs8Ftd11XNyKPsN3pmlKD63M+urqtYS2DYMFsmOOV/2dNiv7BmbNb5kV9f4AfpaykfL/9TZIN2NtcmN0UJzcEcLLw3NMh+6fBToiaFZPvGDs7x1XzdvvLYz59fvafERjhXOnnnDwC8i20TkByJyWkROisgHzPu/JCIvmn8GROTFNZ5/r4i8IiJnReTDdi5eRGwfyBJciLAQjtGXpaIHjEzA7lJPuW7sWlzf3cB8OMaFLC9LZ7Js3rIwbBtKk/GXO1e1BxCxV9ljjVzsXCPjH55dtn0mxnwomlUyF08ofnTOGGlYrM7qQztbiCdUchY2QDgW53e+/CItATf/9c3X5vX6hZZ0ZpLxx4APKaWuAW4H3i8ie5VSb1dK3aSUugn4GvDI6ieKiBP4BPAmYC/wDhHZa9vqsX8Eo5XBZCvlBKPGvxiJ2XJ5FosnGJ0LlX/Gn+MG78xSdgZtFoZtQ/Ey/lA0TnAhXPYbu2A0e21v9tlq3WBN3koX+Pta/Shlf3D60389xX3/64fMLkU3Phg4OWyNNCyeg+3N25twOx08fXal3PPx75zh1bEF/vLnbqAhC9FCOgot6dww8CulRpRSz5u354HTQLf1uBhfsb8APJTm6QeAs0qp80qpCPAwcL8dC7ewe+i6JU/bkUON3+9xoRS2ZP0jsyHiCVX2mebujjrczuw3eGeXIzTkYHhmZfyFHk1nMTxT/lLOVPZ01vGKjaWe0dkQLoek3djubSmMsuf0yDyTixE+/t1XMzr+qSLo91fjrXGyr6cxucH7/MVpPvnkOR64dRt372nP+/W3Nhn2zIXy7Mmqxi8ivcA+4EjK3XcCY0qpM2me0g1cSvl5kJQvjVWv/aCIHBORYxMTExmvqaPOXr+e88FFapxCV2PmPj0Wdg5jGUxKOcu71ON2Obh6Sx0vDWYb+KMZzdpdTWvATTSumAsVZzLVZpFyWuzpqGNgcsm28svobIiOem/aje1CaPmVUgwEF3E7HXz+mQsZXb08fXaSqzvrstLK28Ghna2cGpljdDbE7375OFsaavnDn7rGltf2uJxsqfcWzKUz48AvIgGMks4HlVKpEzjeQfpsHyBdwS1tqqaU+qRSar9San9bW1umy6K93sNiJG7bpupAcJGeZh+uDO2YU/G77Zu7O5hs3ir/gHNddwMnhmezysJnlrJz5rQotpZ/sMx7KVazu7OOeEJxfsKeYDwyG0pb5gFDkdXid9urIlqIMB+O8b67d+J3O/mTb55c931ViDGLmXJwZwtKwXs/9yzng4v81dtu2NBvPxu2FVDSmVF0E5EajKD/RaXUIyn3u4C3Al9a46mDwLaUn7cCtk6LsHsSV39wMaeNXUjJ+G34EhqaMTX8OVx5FJvruxuYD8UyfpMqpYzpW7kEfqt7t0ha/qHpZZwOSatqKUcsZc8rY/lNR7MYnVs78IOR9dtZ6rFe6+aeRn7n9bs5fHaSJ06OrXm8NdLwNbuKP6HOGIfq4PTIHL98cDuHbO4hKKSWPxNVjwCfBk4rpT626uHXAS8rpdYaDPossEtE+kTEDTwAPJrPgldj2TbYEfgTCcXAZB6B38aB64PTy3TUebOWO5aCbGfwhqIJIrFEVhp+C2siWrEy/qEZo5cilyvAUtDb6qfGKbwymv9QFqWU0bW7zpdeb4u9Wv7UPbZ33r6d3R0B/uyxU2uWrg6fC+JyCAdKMJrU43Lymqta6Wv18+E3XW3766faM9tNJu/mO4B3AfekyDfvMx97gFVlHhHpEpHHAJRSMeA3gScwNoW/rJQ6advqWRmGbofedWQuRDiWyEnRA4aqB+yq8Ze/ht/C2uDNNPCvGLTlVuMHoyRQDDaLlNOixulgZ1vAFmXP3HKM5Wh83Yy/r9XH6FzINqNEa4+tu6kWl9PBH7/5Wi5NLfOpH55Pe/xTZye5sQBjFjPlf79jH4/+5h343Pb//kLaM2ei6nlKKSVKqRss+aZSygrs71FK/f2q44eVUvel/PyYUmq3UmqnUurP7P4H2FnqsbKNXDN+OweuD5apD3863C4HezrrMlb2zObg02PRVGRr5lL58OfD7g57lD0jc2tr+C1WNnjtCU79wQW2t/hxmpvJh65q5d5rO/nED84lewosZpejvFSgMYuZ4nO7bK3rp2JJOguh7Nkc16/rEPC48LmdtjRxnc8z8PtsqvHH4glGZkNlr+hJ5bruek4MzWW0wZt05syh1FPjdNDoqylKE5fVS7GZMn4wJJ1DM8tXdJVmy+iqyVvpsD4rdm3w9gcXkzJRiz/8qWuIK8V/f+zly+5/poBjFsuBQmr5N33gFxHbJnENBBeprXEm9w2yJZAcv5hf4B+dMzT8myXjB0PZM7sc5dLU8obHWoE/1yaXFr+7KH491v/DZsv4rQ3eM+P51fmtwL/eCFI7tfzGHtsSO9ouD/zbmn28764dPHp8+LJO2acLPGax1DT73fgLZM+86QM/2NfE1R9cZHuLL2czLp9Z48+3gWtwEwz+WE02G7yzZo0/l81dMEoPIwUYMbiazeDDnw67pnGNzIYQWTFDTIff46K9zmOLln94dplILJH2ivt9d+9kS4OXP370ZNJ9tNBjFkuNiLCt2VcQLX9FnLGOei9jNtg2DAQXr8g2sqHG6cDtcuRd6tkszVup7Omso8YpGQX+lSEsuTkXdjXUJjtqC8lma96y6G6sxed25u3ZMzYXojXg2TCw9rbaM3+3f51Sq8/t4iP3XcPJ4Tm+fOwSo7OFH7NYDhRK0lkZgd8s9eTTxh+LJ7g4tXRFfTFbAp785+5au/i5dA+XCo/Lye6OzDZ4Z5ejuBySbHjLlq7GWsbnwwWf97pZM36HQ9hlwwbvSJrJW+noa7FHy79e4Ad48w1bONDbzF898QqPnxgBKOnGbjEolD1zZQT+ei+haIL5PDLtwellYgmV88auhc+d/9zdoellOuo9m0LDn8oNWxs5fmlmQ93xzLLRtZurk2JXoxel7J+8tpqhmWVaA268NZvr/wFgT0f+ks7Rdbp2U+lt9Rsdt3luJvcHF/G5nbSvYb0gIvzRm/cyvRThz7/1Ms1+N9d0FnbMYqnZbtozj9tsz1wRgb/dlHTmM5Blo2wjUwKe/D35N4Mdczp+dl838+EY33hxaN3jZpeiOdf3wcj4gYKXe4Y2iQ9/OvZ01hNciOS1CT46d+XIxXT02STptLrm10sIrutu4B0HeojEEhzc2VL2w3HypVD2zBUR+Fdm7+b+Jrcr8Bue/HkG/pnN07yVyq29TVyzpZ5/enpg3UvTmeVIXoHfGkVZ6A3eoenNp+G3SA5lyTHrX4rEmF2OrqvosbA+M/151vn7g4sZNU/+7hv2cFV7gJ/JcpbtZiQp6bRZy18Rgd+6NMzn0r8/uEid15XzqDQLn9vJQh6lnlg8wchM+fvwp0NEeM+h7bw8Os+R/qk1jzMM2nI/z9bex1ABM/5EQm2ayVvp2N1p2IrnquzJRMNvsd3sMM1H2ROJJRicXk4OcV+PZr+b7/7Oa/OacLVZ6DbtmXXGn4Z2GzL+gclFdmxwmZkJgTzn7o7NGzNON2OpB+D+m7pp9NXwucMDax4zm+P0LQuf20WTr6agpZ6x+RCRWCJ5qb3ZaAt4aPLV8MpYblp+K/BnUuP31jjpavDmFfgvTS8Rt2GPrdIolD1zRQT+gMdFwOPKO+PP1aMnFb/HxVI+m8xTm8eOOR3eGicP3NrDt0+NrpmRzy7l5syZypaG2oKWek4NG+6W12zZnJuHIsLujrqcSz3W5C2rrLYRva3+vEo9/RP2lForkULYM1dE4AdjgzdXo7ZQNM7QzLItbzq/25nX5u7gJpUQpvLO23sA+MIzF654LBo31Fe5GLSl0tVYWC3/Zg/8YPRWvDo6n5MU0PpSzdSOOl97Zrv22CqRnmZf1jOtN6JiAn8+k7guTS2hlD1vOmvgeq66Wyvwd23iwL+1yccb9nby0NGLV9jpzpkGbbmMXUylq9Fb2MA/Mkdvi69kro92sLujjvlwjOEcroxGZ0M01NZQm2GvRV+Ln5mlKDNLuZnn9U8u0uSryWvvp1LZ3uJjwmZ75soJ/PWenLt38zVnS8XvcRFLKMI5NhcNTi/RXufZlNrxVN59qJeZpSiPvnj53J2Z5fy6di26GmuZC8Xy1o6vxamROfZ2bd5sH+DqPKwbMpVyWiSVPTlm/f0Tuc/BqHSsfaZLNtozV0zgb6/3MjaX2xBua1PKlhp/cvxibuWeoZnNY8e8HrfvaObqzjo+u0raaVky51vjt66IClHnnw9FuTC5xN5NXOYB2JWcxpVD4Ddn7WZKb54unXbtsVUihZB0Vk7gr/MQiSWSgSUb+oOLtAbc1Nvgq22NX8zVqG2zNm+tRkR496FeTo/M8ezAdPL+2TwsmVPpMrPRQpR7To8YgXKzZ/wNtTVsafDmlPGPzGaX8fc0+3AI9OfQxLUUiTE6F8pIylmNFMKeuWICfz5NXOk8wHPFCvy5bPDGE4rhCsn4Ad5yUzcNtTX809MDyfuS07dsKPUADM/Yn/GfGjb8hvZuabD9tYvN7o66rDP+SCzB5GI4IymnhdvloLupNidJp9Xx29cayPq51UCz302z381zF6Y3PjhDKjDwZx8I8hmwvpp8Bq6PzYU2tYZ/NbVuJw/cuo3HT44mM/OkF3+eGX97nQeHcMVUJjs4NTJHi9+dnO62mdnTWceZ8YWklXEmjM+HUCpzRY9Fb0tuLp1a0bM+IsL9N3Xx7VOjts2arqDAb/r1ZCnpXAzHGJ8P21ZfDCTn7mZf6lmxY66MjB/gnbdvRynFF48Y0k4r8Nd781PLuJwOOuu9BenetTZ2823mKwd2d9QRiSWyCsjZNG+l0tfqp39iMet9tv6g0WTW21oZCU8heMeBHqJxxSPPr++DlSkVE/itYRHZZvxWtmFXfdEaupxLxm/ZMVdS4N/W7ON113Tw0NFLhKJxZpej1HlduJz5v/UKoeWPxhO8Orqw6Td2LXJR9mTbvGXR1+pnPhxjcjE7SWd/cInOem9BBpZXCrs76ri5p5GHnr1oi0VzxQT+WreTOq8ra4dOKxOyL+PPvcZfCRr+dLznUC9TixG+eXzYsGvIU9FjsaXR/u7dcxMLROKJTb+xa3FVewCR7JQ9uWb8K4PXsyv39AcXdJknAx440MP5iUWO2VDrr5jAD+Ykriw3d61Wcbs2d32mnDMX24bB6SXaKkDDv5qDO1vY3RHgc08PML0Uybtr16Kr0cvITIhEFvXrjTg5ZHTsVkrG761x0tviz8q6YWQ2RG2NM+tyXF+O83f7g4v05TH5rlr46Ru2UOdx8dDRi3m/VoUF/uybuPonF9nS4M24Q3Ejkpu7Odb4K6nMY2FJO08Oz/HcwHTeG7sWXQ21ROKJrEsL63FqZA5vjYMdbZWjMNndEchqGpfVvJXtHsfWplpcDslqP2FmKcL0UjT5paFZG5/bxc/c1MVjL43kJFtPpbICf132Q9ftVPQAeFwOXA7JqcZvNG9V5gbXz+7rpt7rYj4cy7t5y6IQA1lODc+xp7MeZwUN+NjTUcfA5NIV9hlrkenkrdW4nA56mn2cycIRVCt6suMdB3oIRRP8ywbDjjaiogJ/e73XlKJlfuk/YHPHoIiY4xezC/yVpuFfjc/t4u23bgPyb96ysHz57Qr8SilD0VMhZR6L3Z11xBOK8xOZZeKjGc7aTceBvmaePjdJOJbZl0wy8OtST0Zc193Add31PHT0Ul6bvBUV+DvqPUTjiumlzC6DrMtMuzsGjfGL2ZV6xudDROOqYgM/wC8f7MUh0BqwRx/fZapOcjEhS8fwbIjZ5WjFbOxa7ElaN8xteGwioRibyy3jB3jjdZ0shGM8fXYyo+P7g4s4BLZV6JVuIXjg1h5Oj8zx48HZnF+jogJ/tpJOK9uwa2PXIpfxiysa/sr9AGxr9vGV9x3kPYd6bXm9Rl8NtTVO2zJ+y4q50jL+3lY/bqeDV0Y3LsEEF41BQNnYNaRyaGcLAY+LJ06OZnR8f3CRbc0+3K6KCkUF5f6buqitcfLws7lv8m54tkVkm4j8QEROi8hJEflAymO/JSKvmPd/dI3nD4jISyLyoogcy3mlGWA1cWUd+G3O+H05DFyvRA1/Om7Z3kxTnuMtLUSELY1e27p3Tw7PIrKifa8UapwOdrRlpuyxpJzZGLSl4nE5+Ymr2/nOqbGMuoXt3mOrBuq8Nfz0DVt49MXhnM0gM/majQEfUkpdA9wOvF9E9orITwD3Azcopa4F/nqd1/gJpdRNSqn9Oa0yQ6w3a6YbvAPmZWaPzeP1Ap7sa/yDU5t/AEsp6G6sZcgmv55Tw3P0tfqTyqxKYk9nHaeG5zaUvo7M5ta8lcq913YyuRjh2MDac5fB2FPRgT83HjiwjcVInG8eH9744DRsGPiVUiNKqefN2/PAaaAb+HXgL5RSYfOx8ZxWYCNtWQ5dPx9cZGuT/ZeZPrcra3fOwenlitTwF5quBvu6dytxY9fiddd0MDoX4qvPD657nPXZybXGD3D3njbcLgdPnBxb97iJ+TBLkbgO/Dlwc08Tu9oDPPTspZyen1XEE5FeYB9wBNgN3CkiR0TkP0Tk1jWepoBvi8hzIvLgOq/9oIgcE5FjExMT2SwribfGSaOvJmMt/8BkYbKNQC6lnpklne3nwJZGLxPz4YxVJGsxuxxlcHq54jZ2LX76hi3s62nkr554Zd335shsiBqn0JJHOc7vcXHnVa08cXJ0XeWJnQOQqg0R4YEDPRy/NMPpkY037VeTceAXkQDwNeCDSqk5wAU0YZR/fg/4sqTv+LhDKXUz8CaMMtFd6V5fKfVJpdR+pdT+tra2bP8dSTLV8iulCjb1x+9x5pTxV3p9vxBYWv6x2fxcC60PT6Vm/CLCH/30Xibmw/x//352zeNGZ0O013lx5NnH8MbrOhmaWebk8NpBSWv48+Ot+7pxOx08nEMnb0aBX0RqMIL+F5VSj5h3DwKPKIOjQAJoXf1cpdSw+fc48HXgQNarzIL2eg9jGTh0TiyEWSzQZabfnV3Gn0hq+CtX0VMoViSd+ZV7rABVqRk/wL6eJn52Xzf/+MN+Lq0x1GM0ywEsa/G6azpwCDx+Ym11T39wEbfLkfw/1GRHk9/Nvdd18vUXhjJuzrPIRNUjwKeB00qpj6U89A3gHvOY3YAbCK56rl9E6qzbwBuAE1mtMEva67wZGbUlPXoKkvG7iMQSROOZzd0dnw9XvIa/UNjVxHVqeI62Ok9SElyp/P69e3CK8Bffejnt46N5aPhTafa7OdDXvK6s0xiA5Mv76qKaeeDANuZCMR57aSSr52WS8d8BvAu4x5Rkvigi9wGfAXaIyAngYeDdSiklIl0i8pj53A7gKRE5DhwF/k0p9XhWK8ySjnoP4/PhDdULlp9IIca9JccvZtjEVS1SzkJgl21DJW/sprKloZb3vXYn//bSCEf7L1fdKKUYmV3OuWt3Nfde28mZ8QXOTaTvH9CKnvw5uKOF3hYfDx/NbpM3E1XPU0opUUrdYEoyb1JKPaaUiiil3qmUuk4pdbNS6vvm8cNKqfvM2+eVUjeaf65VSv1ZTv+6LOio9xJPqA2Nu84HF3E7HQWxQLYGri9k2MRVDc1bhcJb46TZ786rezcSS3B2fL6iyzypPHjXDrY0ePlv/3rysgRpbjlGKJqwJeMHeMO1nQBps/54QnFxckmPW8wTEeHtt/ZwdAPp7Goqrl0u0yaugeAiPS2+gphxZTt+UWf8+dHV6M0r4z8zPk80rqoi4wdjdsWH33Q1J4bmLpN3jswZ5zAfDX8qXY213LC1Ia2sc3hmmUg8QZ+eupU3b7tlK64s41jFBf528zJ1YoMNXjsHrK/Gb41fzDjwL9Ma0Br+XNmSp5b/VBVs7K7mZ27sukLeOZIcwGLfrOE3XtvJ8UszV3RXr0g5dcafL211Hl53TUdWz6m4wG91766n8kgkFAOTS+wokCOgPzl+MdMav5Zy5kN3Yy0jeXTvnhyeo9YcWFItpJN3rkzesu+9+Eaz3PPtVVl/v1n31zV+e3jgwLasjq+4wN8W8OB2OvjP3zjBT/3vH/In3zzJ4ydGLptOPzy7TCSWKGDGbw1jybzU060Df850NXqZD8eYC+U2nOLUyBzXbKmrKA/+TFgt7xydDSEC7XX2ZfxXtQfY2ea/os7fH1ykzuOiNWCPb1O1c9eu7HqfKs6UxO1y8LVfP8T3Xh7jaP8UDx29yGcPDwCwqz3Agb5m6k0/+EJlG9nU+A0Nf4g3XtdZkLVUA1ZNemQmRH1ndl7/SilOD89x/76uQiyt7Pn9e/fw+IlR/uJbLxPwuGgNeKhx2psP3ntdJ3//H+eZXowkDfr6J5fobfVnPeVLk55sJbEVF/gBrt/awPVbGwBDsfHS0AxH+qc42j/Fv7w4nKxp7ixUqSeLGv/EQphIPKEVPXmQKunck6Wz5uD0MvPhGHu3NBRiaWWPJe/8+HdfpaPeY0vz1mreeG0nn/jBOb57eoyf32+UJPqDC+zb1mT779JkRkUG/lTcLge3bG/mlu3N/MbdEIsnOD0yz3w4mtwItptAFnN3taInf6wmrqEcNniroWN3Ix68awcPP3uRkdkQN25ttP31r+9uoKvByxMnR/n5/dsIx+IMTS/z1n1bbf9dmsyouBr/RricDq7f2sChnVe4S9hGbY0TkcwyfkvDv00H/pxpr/PidEhOvvynRuZwyMqUqmrEkncCBcn4RYQ3XNvJk2eCLIZjXJpaIqEomLhCszEVn/GXAhHJ2K/HCvzdjbrUkytOh9BZ72U4B2XPqeFZdrQFqHVXt5T2Z27s4uXReV6/NztZYKa88dpOPvf0AP/x6kRSc15NKqpyQwf+AuFzOzOybBicXqI14K76wJMvuTZxnRqe49a+5gKsaHMhIvw/915dsNe/tbeJJl8Nj58Y5VqzrFYInyxNZujAXyACHldGlg2D08t0643dvOlqrOX5i9NZPWd6McLwbKhqOnZLicvp4PV7O/jWS6O4nEJrwE1DbXYKLI19VF2Nv1j4Pa6Ma/x6Yzd/uhprGZ0NbWjOl0rSg7+KN3aLyRuv7WQ+bDhJ6jJPadGBv0BkUupJJBRD08ts1ZO38qarwUs0rgguZD6Q5ZQZ+K/RGX9RuOOqVvxuJ6FoQnfslhgd+AtEJuMXXxmbJxJP6FqnDVha/mwknSeH5+io99AasK9TVbM23hond1/dDkCfVvSUFB34C4Tf42Jpgxr/Px+5iNvl4N5rddduviS7d7OwZz41PMe1XdXZuFUqLO+eQszB0GSO3twtEH6Pk4V1Sj0L4RiPPD/IT9+wJdnGrsmd7iwHsoSicc5OLBRMvqhJz33XdbL01uu552p93kuJDvwFwu9ef3P3Gy8MsRiJ887btxdxVZVLfa0Lv9uZcannzNgC8YTSG7tFxuV08MCBnlIvo+rRpZ4C4fO4WI7GiadRmSil+MIzF9i7pZ592xqLv7gKRETYkoU986mRWQAt5dRUJTrwF4iAadSWrs7//MVpXh6d510Ht2t3Qhvpaqxddw5DKieG5vC7nfQ06x4KTfWhA3+BWLFmvrLO//kfXaDO4+L+m6rTCrhQdDVkZtsQiSX41olRDu5sydrOVqOpBHTgLxDJKVyrMv7JhTCPvTTKW2/uxufWWyx20tVYS3AhTCi6fv/Et0+NElwI80u36f0VTXWiA3+BWGsYy1eeGyQST/BLelPXdiwt/+gGks4vPHOBrU213LU7u6lFGk2loAN/gVgZxrKSfSYSii8eucBtfc3srmIb4ELR1bDxvOWz4/M8c36KX7ytp+pGLWo0FjrwF4iVgesrGf9/nJng0tSylnAWiJVJXGtn/F945iI1TuEX9mc3nFqjqSR04C8Q6Qauf/GZC7QGPMnuRY29dJoZ/8gaWv6lSIyvPT/Im67bom0aNFWNDvwFYnWpZ2hmme+/PM7bb92K26VPeyHw1jhpDbjXLPV88/gw86GYvuLSVD06AhWI1Zu7Dx25CMA7dNdiQelqrGVojVLPF565yO6OALf26iHfmupmw8AvIttE5AciclpETorIB1Ie+y0RecW8/6NrPP9e85izIvJhOxdfzlg1/oVwjEgswcPPXuSeq9vZqoeuFJQtDd60pZ7jl2Z4aWiWd96um+Y0mkyE5DHgQ0qp50WkDnhORL4DdAD3AzcopcIi0r76iSLiBD4BvB4YBJ4VkUeVUqfs+yeUJ06H4K1xsBSJ8cTJUYILES3hLAJdjbU8dSaIUuqyAP+FZy7gczv52X3dJVydRlMebJjxK6VGlFLPm7fngdNAN/DrwF8opcLmY+Npnn4AOKuUOq+UigAPY3xZVAWGJ3+cLzxzgW3Ntbx2l9aNF5quhloWI3HmQiub6rNLUb7542Huv6mbOq8e96fRZFXjF5FeYB9wBNgN3CkiR0TkP0Tk1jRP6QYupfw8aN6X7rUfFJFjInJsYmIim2WVLX6Pi+OXZjjSP8Uv3bZd2wMUga409sxffX6QUDTBO2/X+ysaDWQR+EUkAHwN+KBSag6jTNQE3A78HvBlubJ4mi7SpR2KqpT6pFJqv1Jqf1tbZWTGPreLUyNzuJ0Ofv6WraVeTlXQ1Wg2cZmBXymjaW5fT6MeuqLRmGQU+EWkBiPof1Ep9Yh59yDwiDI4CiSA1lVPHQRSO2W2AsP5LXnzYDl03nd9Jy1aN14Ukhm/advwo3OTnJ9Y5J3al0ejSZKJqkeATwOnlVIfS3noG8A95jG7ATcQXPX0Z4FdItInIm7gAeBRG9a9KbBM2N51UAedYtEW8FDjlGTG/4UjF2j01fBTN2wp8co0mvIhE1XPHcC7gJdE5EXzvj8APgN8RkROABHg3UopJSJdwKeUUvcppWIi8pvAE4AT+IxS6qTt/4oyZU9nHcuRODf3aN14sXA4hI56L8Mzy4zPhfj2yTHee0cv3hpnqZem0ZQNGwZ+pdRTpK/VA7wzzfHDwH0pPz8GPJbrAjczf3DfNVfICjWFp8ucxPXws5eIJZS2X9ZoVqE7dwuMDvrFp7uxlkvTSzx09CJ37mqlt9Vf6iVpNGWFDvyaimNLg5eR2RAjsyHty6PRpEEHfk3FYSl7tjR4+cmrr2go12iqHh34NRWHpeV/4NYeXE79FtdoVqM/FZqK47a+Fn7ljj7efUiXeTSadOhp35qKw+9x8Udv3lvqZWg0ZYvO+DUajabK0IFfo9Foqgwd+DUajabK0IFfo9Foqgwd+DUajabK0IFfo9Foqgwd+DUajabK0IFfo9FoqgxRKu0kxJIiIrPAmXUOaQBmN3iZjY5p5crBMdm+hh3ryOQYvdbCHFMua83kNfRaC/MaG621WO9FO9a6SymV2XxRpVTZ/QE+mc/jGb7GsXJYh16rXmuGr6HXWoK1FvG9WJS1Wn/KtdTzzTwfz/SYclmHXmth1rFZ1mrHOu36PXqt9q8jk2OKtVagTEs9xUBEjiml9pd6HZmg11oY9FoLg15rYbBzreWa8ReDT5Z6AVmg11oY9FoLg15rYbBtrVWb8Ws0Gk21Us0Zv0aj0VQlOvBrNBpNlVFRgV9EPiMi4yJyIuW+G0XkRyLykoh8U0TqzftrROSfzPtPi8hHUp7z7yLyioi8aP6xfXBrlmt1i8hnzfuPi8jdKc+5xbz/rIj8bxGRMl5rQc+riGwTkR+Y/58nReQD5v3NIvIdETlj/t2U8pyPmOfuFRF5Y8r9BT2vNq+1rM6riLSYxy+IyN+ueq2yOq8brLXczuvrReQ58/w9JyL3pLxWduc1U93nZvgD3AXcDJxIue9Z4LXm7V8B/tS8/YvAw+ZtHzAA9Jo//zuwv4zW+n7gs+btduA5wGH+fBQ4CAjwLeBNZbzWgp5XYAtws3m7DngV2At8FPiwef+Hgb80b+8FjgMeoA84BziLcV5tXmu5nVc/8BrgfcDfrnqtcjuv66213M7rPqDLvH0dMJTrea2ojF8p9SQwteruPcCT5u3vAD9nHQ74RcQF1AIRYK4Y64Ss17oX+J75vHFgBtgvIluAeqXUj5Txv/9/gLeU41rtXlM6lFIjSqnnzdvzwGmgG7gf+CfzsH9i5Rzdj/HlH1ZK9QNngQPFOK92rdXONdm1VqXUolLqKSCU+jrleF7XWmsxyGGtLyilhs37TwJeEfHkcl4rKvCvwQngZ8zbPw9sM29/FVgERoCLwF8rpVKD22fNy7v/UojySZZrPQ7cLyIuEekDbjEf6wYGU54/aN5Xjmu1KMp5FZFejAzpCNChlBoB48OGcSUCxrm6lPI06/wV9bzmuVaLcjqva1GO53UjyvW8/hzwglIqTA7ntRoC/68A7xeR5zAupyLm/QeAONCFcen8IRHZYT72S0qp64E7zT/vKvFaP4Pxn3kM+J/A00AM47JuNcXS52a7VijSeRWRAPA14INKqfWu4tY6f0U7rzasFcrvvK75EmnuK/V5XY+yPK8ici3wl8D/bd2V5rB1z2vFB36l1MtKqTcopW4BHsKojYJR439cKRU1SxKHMUsSSqkh8+954J8p3iV12rUqpWJKqd9WSt2klLofaMQwsRsEtqa8xFZgmCKQw1qLcl5FpAbjQ/RFpdQj5t1j5uWwVW4YN+8f5PKrEev8FeW82rTWcjyva1GO53VNyvG8ishW4OvALyulrFiW9Xmt+MBv7cSLiAP4z8Dfmw9dBO4RAz9wO/CyWaJoNZ9TA/w0RlmjZGsVEZ+5RkTk9UBMKXXKvAycF5HbzcvQXwb+pRzXWozzap6DTwOnlVIfS3noUeDd5u13s3KOHgUeMOukfcAu4Ggxzqtday3T85qWMj2va71O2Z1XEWkE/g34iFLqsHVwTud1vZ3fzfYHI/McAaIY34K/CnwAY7f8VeAvWOlWDgBfwdgkOQX8nlrZ5X8O+LH52P/CVE+UcK29wCsYmz/fBbanvM5+jDfkOeBvreeU21qLcV4x1BnK/B0vmn/uA1owNpzPmH83pzznD81z9wopSohCn1e71lrG53UAQxCwYL5n9pbxeb1ireV4XjESrMWUY18E2nM5r9qyQaPRaKqMii/1aDQajeZydODXaDSaKkMHfo1Go6kydODXaDSaKkMHfo1Go6kydODXVAUi8sci8rvrPP4WEdmbwetcdpyI/DcReZ1d69RoioEO/BqNwVsw9NtZHaeU+iOl1HcLtCaNpiDowK+pWETkD8XwU/8uhpsoIvJrIvKsGLMCvmZ2Gh/CMJz7K9OQa6f553ExfM9/KCJXr3Hc50TkbeZrD4jIn4sxp+CYiNwsIk+IyDkReV/Kun7PXMOPReRPSnBqNFWOq9QL0GgKgYjcAjyA4XjoAp7H6MR8RCn1j+Yx/y/wq0qpvxGRR4F/VUp91Xzse8D7lFJnROQ24O+UUvekOW71r76klDooIh8HPgfcAXgxuj//XkTegGG3cADDXOtREblLGdbXGk1R0IFfU6ncCXxdKbUEYAZsgOvMgN+IYdvxxOonmm6Jh4CvpAR2T4a/1/o9LwEBZRh8zYtIyPRaeYP55wXzuADGF4EO/JqioQO/ppJJ50fyOeAtSqnjIvIe4O40xziAGaXUTTn8zrD5dyLltvWzCyPL/+9KqX/I4bU1GlvQNX5NpfIk8LMiUisidcCbzfvrgBHTcfGXUo6fNx9DGZ7o/SLy82C4KIrIjauPy5EngF8xryoQkW4pwExnjWY9dODXVCTKGGn3JQwHw68BPzQf+i8YU46+A7yc8pSHgd8TkRdEZCfGl8KvishxjPr8/Wscl+26vo3h7f4jEXkJYxJcPl8kGk3WaHdOjUajqTJ0xq/RaDRVhg78Go1GU2XowK/RaDRVhg78Go1GU2XowK/RaDRVhg78Go1GU2XowK/RaDRVxv8PHPniuMAcK6oAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "df.Nino34.resample('1Y').mean().plot();" ] }, { "cell_type": "markdown", - "id": "f000116f", + "id": "16c80788", "metadata": {}, "source": [ "### Applying operations to a dataframe\n", @@ -4224,8 +964,8 @@ }, { "cell_type": "code", - "execution_count": 49, - "id": "dcee58a6", + "execution_count": null, + "id": "c8afa857", "metadata": {}, "outputs": [], "source": [ @@ -4239,7 +979,7 @@ }, { "cell_type": "markdown", - "id": "9c38ec17", + "id": "4fbef115", "metadata": {}, "source": [ "Now, this function accepts and returns a single value" @@ -4247,21 +987,10 @@ }, { "cell_type": "code", - "execution_count": 50, - "id": "735d982b", + "execution_count": null, + "id": "34892381", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "273.15" - ] - }, - "execution_count": 50, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# Convert a single value\n", "convert_degc_to_kelvin(0)" @@ -4269,7 +998,7 @@ }, { "cell_type": "markdown", - "id": "434e497a", + "id": "384a0bdb", "metadata": {}, "source": [ "But what if we want to apply this to our dataframe? We can subset for Nino34, which is in degrees Celsius" @@ -4277,40 +1006,17 @@ }, { "cell_type": "code", - "execution_count": 51, - "id": "e406e427", + "execution_count": null, + "id": "f09ee7c6", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "datetime\n", - "1982-01-01 26.72\n", - "1982-02-01 26.70\n", - "1982-03-01 27.20\n", - "1982-04-01 28.02\n", - "1982-05-01 28.54\n", - " ... \n", - "2020-12-01 25.53\n", - "2021-01-01 25.58\n", - "2021-02-01 25.81\n", - "2021-03-01 26.75\n", - "2021-04-01 27.40\n", - "Name: Nino34, Length: 472, dtype: float64" - ] - }, - "execution_count": 51, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "nino34_series" ] }, { "cell_type": "markdown", - "id": "f42069a5", + "id": "28ac04e8", "metadata": {}, "source": [ "Notice how the object type is a pandas series" @@ -4318,28 +1024,17 @@ }, { "cell_type": "code", - "execution_count": 52, - "id": "7b000088", + "execution_count": null, + "id": "8718a43f", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pandas.core.series.Series" - ] - }, - "execution_count": 52, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "type(df.Nino12[0:10])" ] }, { "cell_type": "markdown", - "id": "68a8f033", + "id": "ff1f569f", "metadata": {}, "source": [ "If you call `.values`, the object type is now a numpy array. Pandas `Series` values include numpy arrays, and calling `.values` returns the series as a numpy array!" @@ -4347,28 +1042,17 @@ }, { "cell_type": "code", - "execution_count": 53, - "id": "1b6f337d", + "execution_count": null, + "id": "61a8255f", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "numpy.ndarray" - ] - }, - "execution_count": 53, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "type(df.Nino12.values[0:10])" ] }, { "cell_type": "markdown", - "id": "fc00faa7", + "id": "2a5693fe", "metadata": {}, "source": [ "Let's apply this calculation to this `Series`; this returns another `Series` object." @@ -4376,40 +1060,17 @@ }, { "cell_type": "code", - "execution_count": 54, - "id": "c721039d", + "execution_count": null, + "id": "ae197a92", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "datetime\n", - "1982-01-01 299.87\n", - "1982-02-01 299.85\n", - "1982-03-01 300.35\n", - "1982-04-01 301.17\n", - "1982-05-01 301.69\n", - " ... \n", - "2020-12-01 298.68\n", - "2021-01-01 298.73\n", - "2021-02-01 298.96\n", - "2021-03-01 299.90\n", - "2021-04-01 300.55\n", - "Name: Nino34, Length: 472, dtype: float64" - ] - }, - "execution_count": 54, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "convert_degc_to_kelvin(nino34_series)" ] }, { "cell_type": "markdown", - "id": "4435c540", + "id": "87871b82", "metadata": {}, "source": [ "If we include `.values`, it returns a `numpy array`" @@ -4417,7 +1078,7 @@ }, { "cell_type": "markdown", - "id": "7c7ea806-7efe-4798-bb9b-f8a395797e24", + "id": "a256f852", "metadata": {}, "source": [ "
\n", @@ -4426,86 +1087,17 @@ }, { "cell_type": "code", - "execution_count": 55, - "id": "9120d05e", + "execution_count": null, + "id": "52ae68ee", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([299.87, 299.85, 300.35, 301.17, 301.69, 301.9 , 301.25, 301.08,\n", - " 301.26, 301.79, 301.96, 302.36, 302.51, 302.28, 302.18, 302.06,\n", - " 302.04, 301.39, 300.22, 299.68, 299.59, 299.02, 298.73, 298.74,\n", - " 298.79, 299.54, 300.01, 300.54, 300.54, 300.01, 299.89, 299.49,\n", - " 299.58, 299.08, 298.56, 298.15, 298.58, 298.82, 299.38, 299.95,\n", - " 300.26, 300.01, 299.84, 299.65, 299.4 , 299.34, 299.34, 299.26,\n", - " 298.94, 299.09, 299.8 , 300.59, 300.65, 300.84, 300.52, 300.3 ,\n", - " 300.48, 300.72, 300.88, 300.85, 301.06, 301.17, 301.62, 301.95,\n", - " 301.9 , 302.18, 301.95, 301.73, 301.54, 301.22, 301.14, 300.75,\n", - " 300.47, 300.37, 300.46, 300.47, 299.63, 299.26, 298.72, 298.39,\n", - " 298.58, 297.77, 297.42, 297.48, 297.68, 298.48, 299.05, 299.84,\n", - " 300.24, 300.13, 299.89, 299.48, 299.4 , 299.41, 299.39, 299.53,\n", - " 299.7 , 300.1 , 300.61, 301.17, 301.21, 300.73, 300.4 , 300.2 ,\n", - " 299.9 , 300.13, 299.87, 300.06, 300.16, 300.08, 300.4 , 301.13,\n", - " 301.5 , 301.51, 301.07, 300.59, 300.22, 300.78, 301.01, 301.52,\n", - " 301.56, 301.78, 301.98, 302.29, 302.14, 301.17, 300.68, 299.79,\n", - " 299.63, 299.49, 299.66, 299.88, 299.84, 300.12, 300.81, 301.74,\n", - " 301.97, 301.43, 300.7 , 299.99, 300.07, 300.08, 300.06, 299.91,\n", - " 299.75, 299.74, 300.42, 301.05, 301.19, 301.14, 300.5 , 300.5 ,\n", - " 300.15, 300.64, 301.02, 301.02, 300.7 , 300.6 , 300.78, 301.08,\n", - " 300.88, 300.74, 300.16, 299.48, 299.11, 298.82, 298.81, 298.72,\n", - " 298.89, 299. , 299.77, 300.51, 300.52, 300.47, 300.24, 299.71,\n", - " 299.5 , 299.39, 299.34, 299.17, 299.11, 299.51, 300.18, 301.18,\n", - " 301.75, 302.09, 302.07, 301.99, 302.08, 302.38, 302.47, 302.41,\n", - " 302.25, 302.01, 301.82, 301.71, 301.62, 299.87, 299.09, 298.64,\n", - " 298.76, 298.49, 298.33, 297.94, 298.05, 298.56, 299.4 , 299.99,\n", - " 300.12, 299.75, 299.5 , 298.74, 298.86, 298.79, 298.27, 298.05,\n", - " 297.8 , 298.34, 299.23, 300.16, 300.27, 300.18, 299.87, 299.6 ,\n", - " 299.36, 299.11, 298.93, 298.74, 298.89, 299.26, 299.99, 300.67,\n", - " 300.75, 300.83, 300.47, 300.02, 299.7 , 299.74, 299.6 , 299.32,\n", - " 299.65, 300.1 , 300.47, 301.09, 301.3 , 301.58, 301.13, 300.94,\n", - " 300.98, 301.2 , 301.42, 301.24, 300.91, 300.64, 300.96, 300.96,\n", - " 300.52, 300.63, 300.58, 300. , 300.11, 300.34, 300.2 , 300.04,\n", - " 299.89, 300.01, 300.25, 300.99, 301.21, 300.91, 300.84, 300.69,\n", - " 300.62, 300.53, 300.46, 300.46, 300.25, 300.11, 300.7 , 301.22,\n", - " 301.35, 301.2 , 300.62, 300.03, 299.78, 299.9 , 299.49, 299.04,\n", - " 298.79, 299.23, 299.72, 300.74, 301.06, 301. , 300.5 , 300.37,\n", - " 300.49, 300.62, 300.88, 300.91, 300.41, 299.96, 300.33, 300.93,\n", - " 300.72, 300.7 , 299.94, 299.35, 298.92, 298.37, 298.21, 298.12,\n", - " 297.86, 297.98, 299.22, 299.98, 300.33, 300.32, 300.34, 300. ,\n", - " 299.59, 299.48, 299.45, 298.89, 298.69, 299.19, 299.82, 300.65,\n", - " 301.18, 301.26, 301.09, 300.68, 300.62, 300.78, 301.34, 301.45,\n", - " 301.22, 301.09, 301.44, 301.51, 300.83, 300.15, 299.24, 298.65,\n", - " 298.22, 298.16, 298.22, 298.1 , 298.08, 298.61, 299.38, 300.17,\n", - " 300.57, 300.61, 300.11, 299.34, 299.13, 298.87, 298.75, 298.68,\n", - " 298.64, 299.18, 299.78, 300.53, 300.95, 301.1 , 300.9 , 300.7 ,\n", - " 300.39, 300.13, 300.16, 299.61, 299.31, 299.47, 300.15, 300.83,\n", - " 300.72, 300.58, 300.06, 299.69, 299.8 , 299.51, 299.8 , 299.68,\n", - " 299.21, 299.33, 300.14, 301.16, 301.46, 301.26, 300.55, 300.17,\n", - " 300.32, 300.32, 300.65, 300.5 , 300.25, 300.44, 300.94, 301.71,\n", - " 302.03, 302.11, 301.97, 302.04, 302.15, 302.3 , 302.75, 302.54,\n", - " 302.32, 302.27, 302.05, 302.02, 301.3 , 300.68, 299.88, 299.43,\n", - " 299.26, 299.11, 299.25, 299.31, 299.4 , 300.02, 300.49, 301.25,\n", - " 301.45, 301.34, 300.76, 299.82, 299.44, 299.38, 298.94, 298.95,\n", - " 298.97, 298.98, 299.63, 300.57, 300.87, 301. , 300.67, 300.26,\n", - " 300.25, 300.7 , 300.79, 300.68, 300.23, 300.56, 301.37, 301.75,\n", - " 301.72, 301.39, 300.78, 300.12, 299.85, 300.46, 300.41, 300.22,\n", - " 300.24, 300.29, 300.97, 301.47, 300.74, 300.45, 300.04, 299.33,\n", - " 298.92, 298.45, 298.49, 298.68, 298.73, 298.96, 299.9 , 300.55])" - ] - }, - "execution_count": 55, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "convert_degc_to_kelvin(nino34_series.values)" ] }, { "cell_type": "markdown", - "id": "de2e5b57", + "id": "65b3cd56", "metadata": {}, "source": [ "We can now assign our pandas `Series` with the converted temperatures to a new column in our dataframe!" @@ -4513,8 +1105,8 @@ }, { "cell_type": "code", - "execution_count": 56, - "id": "1ca04877", + "execution_count": null, + "id": "2d84dfe1", "metadata": {}, "outputs": [], "source": [ @@ -4523,40 +1115,17 @@ }, { "cell_type": "code", - "execution_count": 57, - "id": "1d997829", + "execution_count": null, + "id": "dd9a0811", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "datetime\n", - "1982-01-01 299.87\n", - "1982-02-01 299.85\n", - "1982-03-01 300.35\n", - "1982-04-01 301.17\n", - "1982-05-01 301.69\n", - " ... \n", - "2020-12-01 298.68\n", - "2021-01-01 298.73\n", - "2021-02-01 298.96\n", - "2021-03-01 299.90\n", - "2021-04-01 300.55\n", - "Name: Nino34_degK, Length: 472, dtype: float64" - ] - }, - "execution_count": 57, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df.Nino34_degK" ] }, { "cell_type": "markdown", - "id": "1bcaf1cd", + "id": "a8c6dba3", "metadata": {}, "source": [ "Now that our analysis is done, we can save our data to a `csv` for later - or share with others!" @@ -4564,8 +1133,8 @@ }, { "cell_type": "code", - "execution_count": 58, - "id": "81b8d46b", + "execution_count": null, + "id": "054428db", "metadata": {}, "outputs": [], "source": [ @@ -4574,249 +1143,17 @@ }, { "cell_type": "code", - "execution_count": 59, - "id": "cd87abc5", + "execution_count": null, + "id": "3f7d378f", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Nino12Nino12anomNino3Nino3anomNino4Nino4anomNino34Nino34anommonthNino34_degK
datetime
1982-01-0124.29-0.1725.870.2428.300.0026.720.151299.87
1982-02-0125.49-0.5826.380.0128.210.1126.70-0.022299.85
1982-03-0125.21-1.3126.98-0.1628.410.2227.20-0.023300.35
1982-04-0124.50-0.9727.680.1828.920.4228.020.244301.17
1982-05-0123.97-0.2327.790.7129.490.7028.540.695301.69
.................................
2020-12-0122.16-0.6024.38-0.8327.65-0.9525.53-1.1212298.68
2021-01-0123.89-0.6425.06-0.5527.10-1.2525.58-0.991298.73
2021-02-0125.55-0.6625.80-0.5727.20-1.0025.81-0.922298.96
2021-03-0126.48-0.2626.80-0.3927.79-0.5526.75-0.513299.90
2021-04-0124.89-0.8026.96-0.6528.47-0.2127.40-0.494300.55
\n", - "

472 rows × 10 columns

\n", - "
" - ], - "text/plain": [ - " Nino12 Nino12anom Nino3 Nino3anom Nino4 Nino4anom Nino34 \\\n", - "datetime \n", - "1982-01-01 24.29 -0.17 25.87 0.24 28.30 0.00 26.72 \n", - "1982-02-01 25.49 -0.58 26.38 0.01 28.21 0.11 26.70 \n", - "1982-03-01 25.21 -1.31 26.98 -0.16 28.41 0.22 27.20 \n", - "1982-04-01 24.50 -0.97 27.68 0.18 28.92 0.42 28.02 \n", - "1982-05-01 23.97 -0.23 27.79 0.71 29.49 0.70 28.54 \n", - "... ... ... ... ... ... ... ... \n", - "2020-12-01 22.16 -0.60 24.38 -0.83 27.65 -0.95 25.53 \n", - "2021-01-01 23.89 -0.64 25.06 -0.55 27.10 -1.25 25.58 \n", - "2021-02-01 25.55 -0.66 25.80 -0.57 27.20 -1.00 25.81 \n", - "2021-03-01 26.48 -0.26 26.80 -0.39 27.79 -0.55 26.75 \n", - "2021-04-01 24.89 -0.80 26.96 -0.65 28.47 -0.21 27.40 \n", - "\n", - " Nino34anom month Nino34_degK \n", - "datetime \n", - "1982-01-01 0.15 1 299.87 \n", - "1982-02-01 -0.02 2 299.85 \n", - "1982-03-01 -0.02 3 300.35 \n", - "1982-04-01 0.24 4 301.17 \n", - "1982-05-01 0.69 5 301.69 \n", - "... ... ... ... \n", - "2020-12-01 -1.12 12 298.68 \n", - "2021-01-01 -0.99 1 298.73 \n", - "2021-02-01 -0.92 2 298.96 \n", - "2021-03-01 -0.51 3 299.90 \n", - "2021-04-01 -0.49 4 300.55 \n", - "\n", - "[472 rows x 10 columns]" - ] - }, - "execution_count": 59, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "pd.read_csv('nino_analyzed_output.csv', index_col=0, parse_dates=True)" ] }, { "cell_type": "markdown", - "id": "33f433ed", + "id": "9327e958", "metadata": {}, "source": [ "---\n", diff --git a/environment.yml b/environment.yml index e632eff59..dd2831ec2 100644 --- a/environment.yml +++ b/environment.yml @@ -10,3 +10,7 @@ dependencies: - sqlalchemy<1.4 - cartopy - xarray + - pip + - pip: + # works for regular pip packages + - pythia-datasets From 09c69f00d29cbc71dc661cb584be4c231bac8fc9 Mon Sep 17 00:00:00 2001 From: Drew Camron Date: Tue, 20 Apr 2021 16:49:13 -0600 Subject: [PATCH 02/15] Init numpy from python-training --- core/numpy/Intermediate NumPy.ipynb | 498 ++++++++++ ...NumPy Broadcasting and Vectorization.ipynb | 893 +++++++++++++++++ core/numpy/Numpy Basics.ipynb | 902 ++++++++++++++++++ core/numpy/array_index.png | Bin 0 -> 47408 bytes core/numpy/solutions/advection.py | 2 + core/numpy/solutions/broadcasting.py | 5 + core/numpy/solutions/heat_index.py | 20 + core/numpy/solutions/slice.py | 3 + core/numpy/solutions/slice_bonus.py | 3 + core/numpy/solutions/sum_row.py | 4 + core/numpy/solutions/vectorized_diff.py | 1 + 11 files changed, 2331 insertions(+) create mode 100644 core/numpy/Intermediate NumPy.ipynb create mode 100644 core/numpy/NumPy Broadcasting and Vectorization.ipynb create mode 100644 core/numpy/Numpy Basics.ipynb create mode 100644 core/numpy/array_index.png create mode 100644 core/numpy/solutions/advection.py create mode 100644 core/numpy/solutions/broadcasting.py create mode 100644 core/numpy/solutions/heat_index.py create mode 100644 core/numpy/solutions/slice.py create mode 100644 core/numpy/solutions/slice_bonus.py create mode 100644 core/numpy/solutions/sum_row.py create mode 100644 core/numpy/solutions/vectorized_diff.py diff --git a/core/numpy/Intermediate NumPy.ipynb b/core/numpy/Intermediate NumPy.ipynb new file mode 100644 index 000000000..cb7dae4f9 --- /dev/null +++ b/core/numpy/Intermediate NumPy.ipynb @@ -0,0 +1,498 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "
\n", + "\n", + "
\n", + "\"Unidata\n", + "
\n", + "\n", + "

Intermediate NumPy

\n", + "

Unidata Python Workshop

\n", + "\n", + "
\n", + "
\n", + "\n", + "
\n", + "\n", + "
\"NumPy
\n", + "\n", + "### Questions\n", + "1. How do we work with the multiple dimensions in a NumPy Array?\n", + "1. How can we extract irregular subsets of data?\n", + "1. How can we sort an array?\n", + "\n", + "### Objectives\n", + "1. Using axes to slice arrays\n", + "1. Index arrays using true and false\n", + "1. Index arrays using arrays of indices" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "\n", + "## 1. Using axes to slice arrays\n", + "\n", + "The solution to the last exercise in the Numpy Basics notebook introduces an important concept when working with NumPy: the axis. This indicates the particular dimension along which a function should operate (provided the function does something taking multiple values and converts to a single value). \n", + "\n", + "Let's look at a concrete example with `sum`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Convention for import to get shortened namespace\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "# Create an array for testing\n", + "a = np.arange(12).reshape(3, 4)\n", + "a" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# This calculates the total of all values in the array\n", + "np.sum(a)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Keep this in mind:\n", + "a.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Instead, take the sum across the rows:\n", + "np.sum(a, axis=0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Or do the same and take the some across columns:\n", + "np.sum(a, axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " EXERCISE:\n", + "
    \n", + "
  • Finish the code below to calculate advection. The trick is to figure out\n", + " how to do the summation.
  • \n", + "
\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# Synthetic data\n", + "temp = np.random.randn(100, 50)\n", + "u = np.random.randn(100, 50)\n", + "v = np.random.randn(100, 50)\n", + "\n", + "# Calculate the gradient components\n", + "gradx, grady = np.gradient(temp)\n", + "\n", + "# Turn into an array of vectors:\n", + "# axis 0 is x position\n", + "# axis 1 is y position\n", + "# axis 2 is the vector components\n", + "grad_vec = np.dstack([gradx, grady])\n", + "print(grad_vec.shape)\n", + "\n", + "# Turn wind components into vector\n", + "wind_vec = np.dstack([u, v])\n", + "\n", + "# Calculate advection, the dot product of wind and the negative of gradient\n", + "# DON'T USE NUMPY.DOT (doesn't work). Multiply and add.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " SOLUTION\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %load solutions/advection.py" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Top\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## 2. Indexing Arrays with Boolean Values\n", + "Numpy can easily create arrays of boolean values and use those to select certain values to extract from an array" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create some synthetic data representing temperature and wind speed data\n", + "np.random.seed(19990503) # Make sure we all have the same data\n", + "temp = (20 * np.cos(np.linspace(0, 2 * np.pi, 100)) +\n", + " 50 + 2 * np.random.randn(100))\n", + "spd = (np.abs(10 * np.sin(np.linspace(0, 2 * np.pi, 100)) +\n", + " 10 + 5 * np.random.randn(100)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "import matplotlib.pyplot as plt\n", + "plt.plot(temp, 'tab:red')\n", + "plt.plot(spd, 'tab:blue');" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By doing a comparision between a NumPy array and a value, we get an\n", + "array of values representing the results of the comparison between\n", + "each element and the value" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temp > 45" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can take the resulting array and use this to index into the\n", + "NumPy array and retrieve the values where the result was true" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(temp[temp > 45])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So long as the size of the boolean array matches the data, the boolean array can come from anywhere" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(temp[spd > 10])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Make a copy so we don't modify the original data\n", + "temp2 = temp.copy()\n", + "\n", + "# Replace all places where spd is <10 with NaN (not a number) so matplotlib skips it\n", + "temp2[spd < 10] = np.nan\n", + "plt.plot(temp2, 'tab:red')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Can also combine multiple boolean arrays using the syntax for bitwise operations. **MUST HAVE PARENTHESES** due to operator precedence." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(temp[(temp < 45) & (spd > 10)])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " EXERCISE:\n", + "
    \n", + "
  • Heat index is only defined for temperatures >= 80F and relative humidity values >= 40%. Using the data generated below, use boolean indexing to extract the data where heat index has a valid value.
  • \n", + "
\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Here's the \"data\"\n", + "np.random.seed(19990503) # Make sure we all have the same data\n", + "temp = (20 * np.cos(np.linspace(0, 2 * np.pi, 100)) +\n", + " 80 + 2 * np.random.randn(100))\n", + "rh = (np.abs(20 * np.cos(np.linspace(0, 4 * np.pi, 100)) +\n", + " 50 + 5 * np.random.randn(100)))\n", + "\n", + "\n", + "# Create a mask for the two conditions described above\n", + "# good_heat_index = \n", + "\n", + "\n", + "\n", + "# Use this mask to grab the temperature and relative humidity values that together\n", + "# will give good heat index values\n", + "# temp[] ?\n", + "\n", + "\n", + "# BONUS POINTS: Plot only the data where heat index is defined by\n", + "# inverting the mask (using `~mask`) and setting invalid values to np.nan" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " SOLUTION\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %load solutions/heat_index.py" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Top\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## 3. Indexing using arrays of indices\n", + "\n", + "You can also use a list or array of indices to extract particular values--this is a natural extension of the regular indexing. For instance, just as we can select the first element:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(temp[0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also extract the first, fifth, and tenth elements:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(temp[[0, 4, 9]])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One of the ways this comes into play is trying to sort numpy arrays using `argsort`. This function returns the indices of the array that give the items in sorted order. So for our temp \"data\":" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "inds = np.argsort(temp)\n", + "print(inds)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use this array of indices to pass into temp to get it in sorted order:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(temp[inds])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or we can slice `inds` to only give the 10 highest temperatures:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ten_highest = inds[-10:]\n", + "print(temp[ten_highest])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are other numpy arg functions that return indices for operating:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.*arg*?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Top\n", + "
" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/core/numpy/NumPy Broadcasting and Vectorization.ipynb b/core/numpy/NumPy Broadcasting and Vectorization.ipynb new file mode 100644 index 000000000..e64bab722 --- /dev/null +++ b/core/numpy/NumPy Broadcasting and Vectorization.ipynb @@ -0,0 +1,893 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "
\n", + "\n", + "
\n", + "\"Unidata\n", + "
\n", + "\n", + "

NumPy Broadcasting and Vectorization

\n", + "

Unidata Python Workshop

\n", + "\n", + "
\n", + "
\n", + "\n", + "
\n", + "\n", + "
\"NumPy
\n", + "\n", + "### Questions\n", + "1. How can we work with arrays of differing shapes without needing to manually loop or copy data?\n", + "1. How can we reframe operations on data to avoid looping in Python?\n", + "\n", + "### Objectives\n", + "1. Use broadcasting to implicitly loop over data\n", + "1. Vectorize calculations to avoid explicit loops" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## 1. Using broadcasting to implicitly loop over data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Broadcasting is a useful NumPy tool that allows us to perform operations between arrays with different shapes, provided that they are compatible with each other in certain ways. To start, we can create an array below and add 5 to it:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "a = np.array([10, 20, 30, 40])\n", + "a + 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This works even though 5 is not an array; it works like as we would expect, adding 5 to each of the elements in `a`. This also works if 5 is an array:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b = np.array([5])\n", + "a + b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This takes the single element in `b` and adds it to each of the elements in `a`. This won't work for just any `b`, though; for instance, the following:\n", + "```python\n", + "b = np.array([5, 6, 7])\n", + "a + b\n", + "```\n", + "won't work. It does work if `a` and `b` are the same shape:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b = np.array([5, 5, 10, 10])\n", + "a + b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What if what we really want is pairwise addition of a, b? Without broadcasting, we could accomplish this by looping:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b = np.array([1, 2, 3, 4, 5])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "result = np.empty((5, 4), dtype=np.int32)\n", + "for row, valb in enumerate(b):\n", + " for col, vala in enumerate(a):\n", + " result[row, col] = vala + valb\n", + "result" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also do this by manually repeating the arrays to the proper shape for the result, using `np.tile`. This avoids the need to manually loop:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "aa = np.tile(a, (5, 1))\n", + "aa" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Turn b into a column array, then tile it\n", + "bb = np.tile(b.reshape(5, 1), (1, 4))\n", + "bb" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "aa + bb" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also do this using broadcasting, which is where NumPy implicitly repeats the array without using additional memory. With broadcasting, NumPy takes care of repeating for you, provided dimensions are \"compatible\". This works as:\n", + "1. Check the number of dimensions of the arrays. If they are different, *prepend* size one dimensions\n", + "2. Check if each of the dimensions are compatible: either the same size, or one of them is 1." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Right now, they have the same number of dimensions, 1, but that dimension is incompatible. We can solve this by appending a dimension using `np.newaxis` when indexing:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bb = b[:, np.newaxis]\n", + "bb.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a + bb" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This can be written more directly in one line:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a + b[:, np.newaxis]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This also works 2D and 1D, etc.:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = np.array([1, 2])\n", + "y = np.array([3, 4, 5])\n", + "z = np.array([6, 7, 8, 9])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "d_2d = x[:, np.newaxis]**2 + y**2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "d_2d.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "d_3d = d_2d[..., np.newaxis] + z**2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "d_3d.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or in one line:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "h = x[:, np.newaxis, np.newaxis]**2 + y[np.newaxis, :, np.newaxis]**2 + z**2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see this one-line result has the same shape and same values as the other multi-step calculation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "h.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.all(h == d_3d)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Broadcasting is often useful when you want to do calculations with coordinate values, which are often given as 1D arrays corresponding to positions along a particular array dimension. For example, taking range and azimiuth values for radar data (1D separable polar coordinates) and converting to x,y pairs relative to the radar location." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " EXERCISE:\n", + "\n", + "Given the 3D temperature field and 1-D pressure coordinates below, calculate: $T * exp(P / 1000)$. You will need to use broadcasting to make the arrays compatible.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Starting data\n", + "pressure = np.array([1000, 850, 500, 300])\n", + "temps = np.linspace(20, 30, 24).reshape(4, 3, 2)\n", + "print(temps.shape)\n", + "#\n", + "# YOUR CALCULATION HERE\n", + "#" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " SOLUTION\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %load solutions/broadcasting.py" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Top\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## 2. Vectorize calculations to avoid explicit loops" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When working with arrays of data, loops over the individual array elements is a fact of life. However, for improved runtime performance, it is important to avoid performing these loops in Python as much as possible, and let NumPy handle the looping for you. Avoiding these loops frequently, but not always, results in shorter and clearer code as well." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Look ahead/behind\n", + "\n", + "One common pattern for vectorizing is in converting loops that work over the current point as well as the previous and/or next point. This comes up when doing finite-difference calculations (e.g. approximating derivatives)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = np.linspace(0, 20, 6)\n", + "a" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can calculate the forward difference for this array with a manual loop as:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "d = np.zeros(a.size - 1)\n", + "for i in range(len(a) - 1):\n", + " d[i] = a[i + 1] - a[i]\n", + "d" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It would be nice to express this calculation as a loop, if possible. To see how to go about this, let's condsider the values that are involved in calculating `d[i]`, `a[i+1]` and `a[i]`. The values over the loop iterations are:\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ia[i+1]a[i]
040
184
2128
31612
42016
\n", + "\n", + "We can express the series of values for `a[i+1]` then as:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[1:]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and `a[i]` as:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[:-1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This means that we can express the forward difference as:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[1:] - a[:-1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It should be noted that using slices in this way returns only a **view** on the original array. This means not only can you use the slices to modify the original data (even accidentally), but that this is also a quick operation that does not involve a copy and does not bloat memory usage." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " EXERCISE:\n", + "\n", + "2nd Derivative\n", + " \n", + "A finite difference estimate of the 2nd derivative is given by:\n", + "$$f''(x) = 2\n", + "f_i - f_{i+1} - f_{i-1}$$\n", + "\n", + "(we're ignoring $\\Delta x$ here)\n", + "\n", + "* Write vectorized code to calculate this finite difference for a (using slices)\n", + "\n", + "What values should we be expecting to get for the 2nd derivative?\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# YOUR CODE GOES HERE" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " SOLUTION\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %load solutions/vectorized_diff.py" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Blocking\n", + "\n", + "Another application where vectorization comes into play to make operations more efficient is when operating on blocks of data. Let's start by creating some temperature data (rounding to make it easier to see/recognize the values)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temps = np.round(20 + np.random.randn(10) * 5, 1)\n", + "temps" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's start by writing a loop to take a 3-point running mean of the data. We'll do this by iterating over all the point in the array and average the 3 points centered on that point. We'll simplify the problem by avoiding dealing with the cases at the edges of the array." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "avg = np.zeros_like(temps)\n", + "# We're just ignoring the edge effects here\n", + "for i in range(1, len(temps) - 1):\n", + " sub = temps[i - 1:i + 2]\n", + " avg[i] = sub.mean()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "avg" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As with the case of doing finite differences, we can express this using slices of the original array:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# i - 1 i i + 1\n", + "(temps[:-2] + temps[1:-1] + temps[2:]) / 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another option to solve this is not using slicing but by using a powerful numpy tool: `as_strided`. This tool can result in some odd behavior, so take care when using--the tradeoff is that this can be used to do some powerful operations. What we're doing here is altering how NumPy is interpreting the values in the memory that underpins the array. So for this array:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temps" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "we can create a view of the array with a new, bigger shape, with rows made up of overlapping values. We do this by specifying a new shape of 8x3, one row for each of the length 3 blocks we can fit in the original 1D array of data. We then use the `strides` argument to control how numpy walks between items in each dimension. The last item in the strides tuple is just as normal--it says that the number of bytes to walk between items is just the size of an item. (Increasing this would skip items.) The first item says that when we go to a new, in this case row, only advance the size of a single item. This is what gives us overlapping rows." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "block_size = 3\n", + "new_shape = (len(temps) - block_size + 1, block_size)\n", + "bytes_per_item = temps.dtype.itemsize\n", + "temps_strided = np.lib.stride_tricks.as_strided(temps,\n", + " shape=new_shape,\n", + " strides=(bytes_per_item, bytes_per_item))\n", + "temps_strided" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we have this view of the array with the rows representing overlapping blocks, we can operate across the rows with `mean` and the `axis=-1` argument to get our running average:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temps_strided.mean(axis=-1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It should be noted that there are no copies going on here, so if we change a value at a single indexed location, the change actually shows up in multiple locations:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temps_strided[0, 2] = 2000\n", + "temps_strided" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Finding the difference between min and max\n", + "\n", + "Another operation that crops up when slicing and dicing data is trying to identify a set of indexes, along a particular axis, within a larger multidimensional array. For instance, say we have a 3D array of temperatures, and want to identify the location of the $-10^oC$ isotherm within each column:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pressure = np.linspace(1000, 100, 25)\n", + "temps = np.random.randn(25, 30, 40) * 3 + np.linspace(25, -100, 25).reshape(-1, 1, 1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "NumPy has the function `argmin()` which returns the index of the minium value. We can use this to find the minimum absolute difference between the value and -10:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Using axis=0 to tell it to operate along the pressure dimension\n", + "inds = np.argmin(np.abs(temps - -10), axis=0)\n", + "inds" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "inds.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great! We have an array representing the index of the point closest to $-10^oC$ in each column of data. We could use this to look up into our pressure coordinates to find the pressure level for each column:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pressure[inds]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "How about using that to find the actual temperature value that was closest?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temps[inds, :, :].shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Unfortunately, this replaced the pressure dimension (size 25) with the shape of our index array (30 x 40), giving us a 30 x 40 x 30 x 40 array (imagine what would have happened with real data!). One solution here would be to loop:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "output = np.empty(inds.shape, dtype=temps.dtype)\n", + "for (i, j), val in np.ndenumerate(inds):\n", + " output[i, j] = temps[val, i, j]\n", + "output" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Of course, what we really want to do is avoid the explicit loop. Let's temporarily simplify the problem to a single dimension. If we have a 1D array, we can pass a 1D array of indices (a full) range, and get back the same as the original data array:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pressure[np.arange(pressure.size)]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.all(pressure[np.arange(pressure.size)] == pressure)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use this to select all the indices on the other dimensions of our temperature array. We will also need to use the magic of broadcasting to combine arrays of indices across dimensions:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now vectorized solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "y_inds = np.arange(temps.shape[1])[:, np.newaxis]\n", + "x_inds = np.arange(temps.shape[2])\n", + "temps[inds, y_inds, x_inds]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's say we want to find the relative humidity at the -10C isotherm" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.all(output == temps[inds, y_inds, x_inds])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Resources\n", + "* [NumPy Broadcasting Documentation](https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html)\n", + "* [NumPy Broadcasting Article](https://numpy.org/devdocs/user/theory.broadcasting.html)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Top\n", + "
" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/core/numpy/Numpy Basics.ipynb b/core/numpy/Numpy Basics.ipynb new file mode 100644 index 000000000..0f636c407 --- /dev/null +++ b/core/numpy/Numpy Basics.ipynb @@ -0,0 +1,902 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "
\n", + "\n", + "
\n", + "\"Unidata\n", + "
\n", + "\n", + "

NumPy Basics

\n", + "

Unidata Python Workshop

\n", + "\n", + "
\n", + "
\n", + "\n", + "
\n", + "\n", + "
\"NumPy
\n", + "\n", + "### Questions\n", + "1. What are arrays?\n", + "2. How can arrays be manipulated effectively in Python?\n", + "\n", + "### Objectives\n", + "1. Create an array of ‘data’.\n", + "2. Perform basic calculations on this data using python math functions.\n", + "3. Slice and index the array" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "NumPy is the fundamental package for scientific computing with Python. It contains among other things:\n", + "- a powerful N-dimensional array object\n", + "- sophisticated (broadcasting) functions\n", + "- useful linear algebra, Fourier transform, and random number capabilities\n", + "\n", + "The NumPy array object is the common interface for working with typed arrays of data across a wide-variety of scientific Python packages. NumPy also features a C-API, which enables interfacing existing Fortran/C/C++ libraries with Python and NumPy." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an array of 'data'\n", + "\n", + "The NumPy array represents a *contiguous* block of memory, holding entries of a given type (and hence fixed size). The entries are laid out in memory according to the shape, or list of dimension sizes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "# Convention for import to get shortened namespace\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "# Create a simple array from a list of integers\n", + "a = np.array([1, 2, 3])\n", + "a" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# See how many dimensions the array has\n", + "a.ndim" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "# Print out the shape attribute\n", + "a.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "# Print out the data type attribute\n", + "a.dtype" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "# This time use a nested list of floats\n", + "a = np.array([[1., 2., 3., 4., 5.]])\n", + "a" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# See how many dimensions the array has\n", + "a.ndim" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "# Print out the shape attribute\n", + "a.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "# Print out the data type attribute\n", + "a.dtype" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "

Poll

\n", + "Please go to http://www.PollEv.com/johnleeman205 to take a quick poll.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "NumPy also provides helper functions for generating arrays of data to save you typing for regularly spaced data. \n", + "\n", + "* `arange(start, stop, interval)` creates a range of values in the interval `[start,stop)` with `step` spacing.\n", + "* `linspace(start, stop, num)` creates a range of `num` evenly spaced values over the range `[start,stop]`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### arange" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "a = np.arange(5)\n", + "print(a)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = np.arange(3, 11)\n", + "print(a)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "a = np.arange(1, 10, 2)\n", + "print(a)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "

Poll

\n", + "Please go to http://www.PollEv.com/johnleeman205 to take a quick poll.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### linspace" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "b = np.linspace(5, 15, 5)\n", + "print(b)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b = np.linspace(2.5, 10.25, 11)\n", + "print(b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "

Poll

\n", + "Please go to http://www.PollEv.com/johnleeman205 to take a quick poll.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "## Perform basic calculations with Python\n", + "\n", + "### Basic math\n", + "\n", + "In core Python, that is *without* NumPy, creating sequences of values and adding them together requires writing a lot of manual loops, just like one would do in C/C++:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = range(5, 10)\n", + "b = [3 + i * 1.5/4 for i in range(5)]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "result = []\n", + "for x, y in zip(a, b):\n", + " result.append(x + y)\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "That is very verbose and not very intuitive. Using NumPy this becomes:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = np.arange(5, 10)\n", + "b = np.linspace(3, 4.5, 5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "a + b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The four major mathematical operations operate in the same way. They perform an element-by-element calculation of the two arrays. The two must be the same shape though!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "a * b" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "### Constants\n", + "\n", + "NumPy proves us access to some useful constants as well - remember you should never be typing these in manually! Other libraries such as SciPy and MetPy have their own set of constants that are more domain specific." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.pi" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.e" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "# This makes working with radians effortless!\n", + "t = np.arange(0, 2 * np.pi + np.pi / 4, np.pi / 4)\n", + "t" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Array math functions\n", + "\n", + "NumPy also has math functions that can operate on arrays. Similar to the math operations, these greatly simplify and speed up these operations. Be sure to checkout the [listing](https://docs.scipy.org/doc/numpy/reference/routines.math.html) of mathematical functions in the NumPy documentation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "# Calculate the sine function\n", + "sin_t = np.sin(t)\n", + "print(sin_t)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Round to three decimal places\n", + "print(np.round(sin_t, 3))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate the cosine function\n", + "cos_t = np.cos(t)\n", + "print(cos_t)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Convert radians to degrees\n", + "degrees = np.rad2deg(t)\n", + "print(degrees)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Integrate the sine function with the trapezoidal rule\n", + "sine_integral = np.trapz(sin_t, t)\n", + "print(np.round(sine_integral, 3))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Sum the values of the cosine\n", + "cos_sum = np.sum(cos_t)\n", + "print(cos_sum)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate the cumulative sum of the cosine\n", + "cos_csum = np.cumsum(cos_t)\n", + "print(cos_csum)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Index and slice arrays\n", + "\n", + "Indexing is how we pull individual data items out of an array. Slicing extends this process to pulling out a regular set of the items." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "# Create an array for testing\n", + "a = np.arange(12).reshape(3, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "a" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "Indexing in Python is 0-based, so the command below looks for the 2nd item along the first dimension (row) and the 3rd along the second dimension (column).\n", + "\n", + "![](array_index.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "a[1, 2]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "Can also just index on one dimension" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "a[2]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "Negative indices are also allowed, which permit indexing relative to the end of the array." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "a[0, -1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "

Poll

\n", + "Please go to http://www.PollEv.com/johnleeman205 to take a quick poll.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "Slicing syntax is written as `start:stop[:step]`, where all numbers are optional.\n", + "- defaults: \n", + " - start = 0\n", + " - stop = len(dim)\n", + " - step = 1\n", + "- The second colon is also optional if no step is used.\n", + "\n", + "It should be noted that end represents one past the last item; one can also think of it as a half open interval: `[start, end)`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "# Get the 2nd and 3rd rows\n", + "a[1:3]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "# All rows and 3rd column\n", + "a[:, 2]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "# ... can be used to replace one or more full slices\n", + "a[..., 2]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Slice every other row\n", + "a[::2]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "
\n", + "

Poll

\n", + "Please go to http://www.PollEv.com/johnleeman205 to take a quick poll.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " EXERCISE:\n", + "
    \n", + "
  • The code below calculates a two point average using a Python list and loop. Convert it do obtain the same results using NumPy slicing
  • \n", + "
  • Bonus points: Can you extend the NumPy version to do a 3 point (running) average?
  • \n", + "
\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data = [1, 3, 5, 7, 9, 11]\n", + "out = []\n", + "\n", + "# Look carefully at the loop. Think carefully about the sequence of values\n", + "# that data[i] takes--is there some way to get those values as a numpy slice?\n", + "# What about for data[i + 1]?\n", + "for i in range(len(data) - 1):\n", + " out.append((data[i] + data[i + 1]) / 2)\n", + "\n", + "print(out)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# YOUR CODE GOES HERE" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " SOLUTION\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %load solutions/slice.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# YOUR BONUS CODE GOES HERE" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " SOLUTION\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %load solutions/slice_bonus.py" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " EXERCISE:\n", + "
    \n", + "
  • Given the array of data below, calculate the total of each of the columns (i.e. add each of the three rows together):
  • \n", + "
\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data = np.arange(12).reshape(3, 4)\n", + "\n", + "# YOUR CODE GOES HERE\n", + "# total = ?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " SOLUTION\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %load solutions/sum_row.py" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Resources\n", + "\n", + "The goal of this tutorial is to provide an overview of the use of the NumPy library. It tries to hit all of the important parts, but it is by no means comprehensive. For more information, try looking at the:\n", + "- [Tentative NumPy Tutorial](http://wiki.scipy.org/Tentative_NumPy_Tutorial)\n", + "- [NumPy User Guide](http://docs.scipy.org/doc/numpy/user/)\n", + "- [SciPy Lecture Notes](https://scipy-lectures.org/)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Top\n", + "
" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/core/numpy/array_index.png b/core/numpy/array_index.png new file mode 100644 index 0000000000000000000000000000000000000000..d1da260209c49b72811605fba8322b9af376d662 GIT binary patch literal 47408 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 80) & (rh >= 0.4) + +# Use this mask to grab the temperature and relative humidity values that together +# will give good heat index values +print(temp[good_heat_index]) + +# BONUS POINTS: Plot only the data where heat index is defined by +# inverting the mask (using ~mask) and setting invalid values to np.nan +temp[~good_heat_index] = np.nan +plt.plot(temp, 'tab:red') diff --git a/core/numpy/solutions/slice.py b/core/numpy/solutions/slice.py new file mode 100644 index 000000000..b5155c33a --- /dev/null +++ b/core/numpy/solutions/slice.py @@ -0,0 +1,3 @@ +data = np.array([1, 3, 5, 7, 9, 11]) +out = (data[:-1] + data[1:]) / 2 +print(out) diff --git a/core/numpy/solutions/slice_bonus.py b/core/numpy/solutions/slice_bonus.py new file mode 100644 index 000000000..c0307f4c7 --- /dev/null +++ b/core/numpy/solutions/slice_bonus.py @@ -0,0 +1,3 @@ +data = np.array([1, 3, 5, 7, 9, 11]) +out = (data[2:] + data[1:-1] + data[:-2]) / 3 +print(out) diff --git a/core/numpy/solutions/sum_row.py b/core/numpy/solutions/sum_row.py new file mode 100644 index 000000000..fa01c199b --- /dev/null +++ b/core/numpy/solutions/sum_row.py @@ -0,0 +1,4 @@ +print(data[0] + data[1] + data[2]) + +# Or we can use numpy's sum and use the "axis" argument +print(np.sum(data, axis=0)) diff --git a/core/numpy/solutions/vectorized_diff.py b/core/numpy/solutions/vectorized_diff.py new file mode 100644 index 000000000..a8c683ab5 --- /dev/null +++ b/core/numpy/solutions/vectorized_diff.py @@ -0,0 +1 @@ +2 * a[1:-1] - a[:-2] - a[2:] From e3727dc934b674ff1b0ce06fc9597cb400e56b63 Mon Sep 17 00:00:00 2001 From: Drew Camron Date: Tue, 20 Apr 2021 17:18:50 -0600 Subject: [PATCH 03/15] Remove branding, refactor solutions, rename notebooks --- ...{Numpy Basics.ipynb => numpy-basics.ipynb} | 153 ++---------------- ...ization.ipynb => numpy-broadcasting.ipynb} | 71 ++------ ...e NumPy.ipynb => numpy-intermediate.ipynb} | 79 ++------- core/numpy/solutions/advection.py | 2 - core/numpy/solutions/broadcasting.py | 5 - core/numpy/solutions/heat_index.py | 20 --- core/numpy/solutions/slice.py | 3 - core/numpy/solutions/slice_bonus.py | 3 - core/numpy/solutions/sum_row.py | 4 - core/numpy/solutions/vectorized_diff.py | 1 - 10 files changed, 41 insertions(+), 300 deletions(-) rename core/numpy/{Numpy Basics.ipynb => numpy-basics.ipynb} (78%) rename core/numpy/{NumPy Broadcasting and Vectorization.ipynb => numpy-broadcasting.ipynb} (91%) rename core/numpy/{Intermediate NumPy.ipynb => numpy-intermediate.ipynb} (81%) delete mode 100644 core/numpy/solutions/advection.py delete mode 100644 core/numpy/solutions/broadcasting.py delete mode 100644 core/numpy/solutions/heat_index.py delete mode 100644 core/numpy/solutions/slice.py delete mode 100644 core/numpy/solutions/slice_bonus.py delete mode 100644 core/numpy/solutions/sum_row.py delete mode 100644 core/numpy/solutions/vectorized_diff.py diff --git a/core/numpy/Numpy Basics.ipynb b/core/numpy/numpy-basics.ipynb similarity index 78% rename from core/numpy/Numpy Basics.ipynb rename to core/numpy/numpy-basics.ipynb index 0f636c407..6f521420b 100644 --- a/core/numpy/Numpy Basics.ipynb +++ b/core/numpy/numpy-basics.ipynb @@ -4,22 +4,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "
\n", + "# NumPy Basics\n", "\n", - "
\n", - "\"Unidata\n", - "
\n", - "\n", - "

NumPy Basics

\n", - "

Unidata Python Workshop

\n", - "\n", - "
\n", - "
\n", - "\n", - "
\n", - "\n", - "
\"NumPy
\n", + "![NumPy Logo](https://github.com/numpy/numpy/raw/main/branding/logo/primary/numpylogo.svg \"NumPy Logo\")\n", "\n", "### Questions\n", "1. What are arrays?\n", @@ -172,16 +159,6 @@ "a.dtype" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "

Poll

\n", - "Please go to http://www.PollEv.com/johnleeman205 to take a quick poll.\n", - "
" - ] - }, { "cell_type": "markdown", "metadata": { @@ -241,16 +218,6 @@ "print(a)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "

Poll

\n", - "Please go to http://www.PollEv.com/johnleeman205 to take a quick poll.\n", - "
" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -282,16 +249,6 @@ "print(b)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "

Poll

\n", - "Please go to http://www.PollEv.com/johnleeman205 to take a quick poll.\n", - "
" - ] - }, { "cell_type": "markdown", "metadata": { @@ -546,19 +503,7 @@ "outputs": [], "source": [ "# Create an array for testing\n", - "a = np.arange(12).reshape(3, 4)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ + "a = np.arange(12).reshape(3, 4)\n", "a" ] }, @@ -636,16 +581,6 @@ "a[0, -1]" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "

Poll

\n", - "Please go to http://www.PollEv.com/johnleeman205 to take a quick poll.\n", - "
" - ] - }, { "cell_type": "markdown", "metadata": { @@ -716,31 +651,11 @@ "a[::2]" ] }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "source": [ - "
\n", - "

Poll

\n", - "Please go to http://www.PollEv.com/johnleeman205 to take a quick poll.\n", - "
" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", - " EXERCISE:\n", - "
    \n", - "
  • The code below calculates a two point average using a Python list and loop. Convert it do obtain the same results using NumPy slicing
  • \n", - "
  • Bonus points: Can you extend the NumPy version to do a 3 point (running) average?
  • \n", - "
\n", - "
" + "The code below calculates a two point average using a Python list and loop, and we can then convert it to obtain the same results using NumPy slicing." ] }, { @@ -767,25 +682,16 @@ "metadata": {}, "outputs": [], "source": [ - "# YOUR CODE GOES HERE" + "data = np.array([1, 3, 5, 7, 9, 11])\n", + "out = (data[:-1] + data[1:]) / 2\n", + "print(out)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", - " SOLUTION\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# %load solutions/slice.py" + "Can we extend the NumPy version to do a 3 point (running) average? Of course!" ] }, { @@ -794,16 +700,16 @@ "metadata": {}, "outputs": [], "source": [ - "# YOUR BONUS CODE GOES HERE" + "data = np.array([1, 3, 5, 7, 9, 11])\n", + "out = (data[2:] + data[1:-1] + data[:-2]) / 3\n", + "print(out)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", - " SOLUTION\n", - "
" + "Given the array of data below, we can calculate the total of each of the columns (i.e. add each of the three rows together):" ] }, { @@ -812,19 +718,7 @@ "metadata": {}, "outputs": [], "source": [ - "# %load solutions/slice_bonus.py" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - " EXERCISE:\n", - "
    \n", - "
  • Given the array of data below, calculate the total of each of the columns (i.e. add each of the three rows together):
  • \n", - "
\n", - "
" + "data = np.arange(12).reshape(3, 4)\n" ] }, { @@ -833,19 +727,7 @@ "metadata": {}, "outputs": [], "source": [ - "data = np.arange(12).reshape(3, 4)\n", - "\n", - "# YOUR CODE GOES HERE\n", - "# total = ?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - " SOLUTION\n", - "
" + "print(data[0] + data[1] + data[2])" ] }, { @@ -854,7 +736,8 @@ "metadata": {}, "outputs": [], "source": [ - "# %load solutions/sum_row.py" + "# Or we can use numpy's sum and use the \"axis\" argument\n", + "print(np.sum(data, axis=0))" ] }, { @@ -863,8 +746,6 @@ "source": [ "## Resources\n", "\n", - "The goal of this tutorial is to provide an overview of the use of the NumPy library. It tries to hit all of the important parts, but it is by no means comprehensive. For more information, try looking at the:\n", - "- [Tentative NumPy Tutorial](http://wiki.scipy.org/Tentative_NumPy_Tutorial)\n", "- [NumPy User Guide](http://docs.scipy.org/doc/numpy/user/)\n", "- [SciPy Lecture Notes](https://scipy-lectures.org/)" ] @@ -894,7 +775,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.8.8" } }, "nbformat": 4, diff --git a/core/numpy/NumPy Broadcasting and Vectorization.ipynb b/core/numpy/numpy-broadcasting.ipynb similarity index 91% rename from core/numpy/NumPy Broadcasting and Vectorization.ipynb rename to core/numpy/numpy-broadcasting.ipynb index e64bab722..9c53c680f 100644 --- a/core/numpy/NumPy Broadcasting and Vectorization.ipynb +++ b/core/numpy/numpy-broadcasting.ipynb @@ -4,22 +4,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "
\n", + "# NumPy Broadcasting and Vectorization\n", "\n", - "
\n", - "\"Unidata\n", - "
\n", - "\n", - "

NumPy Broadcasting and Vectorization

\n", - "

Unidata Python Workshop

\n", - "\n", - "
\n", - "
\n", - "\n", - "
\n", - "\n", - "
\"NumPy
\n", + "![NumPy Logo](https://github.com/numpy/numpy/raw/main/branding/logo/primary/numpylogo.svg \"NumPy Logo\")\n", "\n", "### Questions\n", "1. How can we work with arrays of differing shapes without needing to manually loop or copy data?\n", @@ -337,11 +324,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", - " EXERCISE:\n", - "\n", - "Given the 3D temperature field and 1-D pressure coordinates below, calculate: $T * exp(P / 1000)$. You will need to use broadcasting to make the arrays compatible.\n", - "
" + "Given the 3D temperature field and 1-D pressure coordinates below, let's calculate $T * exp(P / 1000)$. We will need to use broadcasting to make the arrays compatible!" ] }, { @@ -353,19 +336,7 @@ "# Starting data\n", "pressure = np.array([1000, 850, 500, 300])\n", "temps = np.linspace(20, 30, 24).reshape(4, 3, 2)\n", - "print(temps.shape)\n", - "#\n", - "# YOUR CALCULATION HERE\n", - "#" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - " SOLUTION\n", - "
" + "print(temps.shape)" ] }, { @@ -374,7 +345,7 @@ "metadata": {}, "outputs": [], "source": [ - "# %load solutions/broadcasting.py" + "temps * np.exp(pressure[:, np.newaxis, np.newaxis] / 1000)" ] }, { @@ -508,10 +479,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", - " EXERCISE:\n", - "\n", - "2nd Derivative\n", + "#### 2nd Derivative\n", " \n", "A finite difference estimate of the 2nd derivative is given by:\n", "$$f''(x) = 2\n", @@ -519,28 +487,7 @@ "\n", "(we're ignoring $\\Delta x$ here)\n", "\n", - "* Write vectorized code to calculate this finite difference for a (using slices)\n", - "\n", - "What values should we be expecting to get for the 2nd derivative?\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# YOUR CODE GOES HERE" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - " SOLUTION\n", - "
" + "Let's write some vectorized code to calculate this finite difference for `a` (using slices.) What values should we be expecting to get for the 2nd derivative?" ] }, { @@ -549,7 +496,7 @@ "metadata": {}, "outputs": [], "source": [ - "# %load solutions/vectorized_diff.py" + "2 * a[1:-1] - a[:-2] - a[2:]" ] }, { @@ -885,7 +832,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.8.8" } }, "nbformat": 4, diff --git a/core/numpy/Intermediate NumPy.ipynb b/core/numpy/numpy-intermediate.ipynb similarity index 81% rename from core/numpy/Intermediate NumPy.ipynb rename to core/numpy/numpy-intermediate.ipynb index cb7dae4f9..e2fe8d429 100644 --- a/core/numpy/Intermediate NumPy.ipynb +++ b/core/numpy/numpy-intermediate.ipynb @@ -4,22 +4,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "
\n", + "# Intermediate NumPy\n", "\n", - "
\n", - "\"Unidata\n", - "
\n", - "\n", - "

Intermediate NumPy

\n", - "

Unidata Python Workshop

\n", - "\n", - "
\n", - "
\n", - "\n", - "
\n", - "\n", - "
\"NumPy
\n", + "![NumPy Logo](https://github.com/numpy/numpy/raw/main/branding/logo/primary/numpylogo.svg \"NumPy Logo\")\n", "\n", "### Questions\n", "1. How do we work with the multiple dimensions in a NumPy Array?\n", @@ -117,13 +104,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", - " EXERCISE:\n", - "
    \n", - "
  • Finish the code below to calculate advection. The trick is to figure out\n", - " how to do the summation.
  • \n", - "
\n", - "
" + "After putting together some data and introducing some more advanced calculations, let's demonstrate a multi-layered example: calculating advection." ] }, { @@ -150,19 +131,14 @@ "print(grad_vec.shape)\n", "\n", "# Turn wind components into vector\n", - "wind_vec = np.dstack([u, v])\n", - "\n", - "# Calculate advection, the dot product of wind and the negative of gradient\n", - "# DON'T USE NUMPY.DOT (doesn't work). Multiply and add.\n" + "wind_vec = np.dstack([u, v])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", - " SOLUTION\n", - "
" + "Moving on to calculate advection, the dot product of wind and the negative of gradient, we multiply and add by hand." ] }, { @@ -171,7 +147,8 @@ "metadata": {}, "outputs": [], "source": [ - "# %load solutions/advection.py" + "advec = (wind_vec * -grad_vec).sum(axis=-1)\n", + "print(advec.shape)" ] }, { @@ -211,7 +188,6 @@ "metadata": {}, "outputs": [], "source": [ - "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "plt.plot(temp, 'tab:red')\n", "plt.plot(spd, 'tab:blue');" @@ -302,12 +278,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", - " EXERCISE:\n", - "
    \n", - "
  • Heat index is only defined for temperatures >= 80F and relative humidity values >= 40%. Using the data generated below, use boolean indexing to extract the data where heat index has a valid value.
  • \n", - "
\n", - "
" + "Heat index is only defined for temperatures >= 80F and relative humidity values >= 40%. Using the data generated below, we can use boolean indexing to extract the data where heat index has a valid value." ] }, { @@ -317,43 +288,23 @@ "outputs": [], "source": [ "# Here's the \"data\"\n", - "np.random.seed(19990503) # Make sure we all have the same data\n", + "np.random.seed(19990503)\n", "temp = (20 * np.cos(np.linspace(0, 2 * np.pi, 100)) +\n", " 80 + 2 * np.random.randn(100))\n", "rh = (np.abs(20 * np.cos(np.linspace(0, 4 * np.pi, 100)) +\n", " 50 + 5 * np.random.randn(100)))\n", "\n", - "\n", "# Create a mask for the two conditions described above\n", - "# good_heat_index = \n", - "\n", - "\n", + "good_heat_index = (temp >= 80) & (rh >= 0.4)\n", "\n", "# Use this mask to grab the temperature and relative humidity values that together\n", "# will give good heat index values\n", - "# temp[] ?\n", - "\n", + "print(temp[good_heat_index]) \n", "\n", "# BONUS POINTS: Plot only the data where heat index is defined by\n", - "# inverting the mask (using `~mask`) and setting invalid values to np.nan" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - " SOLUTION\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# %load solutions/heat_index.py" + "# inverting the mask (using ~mask) and setting invalid values to np.nan\n", + "temp[~good_heat_index] = np.nan\n", + "plt.plot(temp, 'tab:red')" ] }, { @@ -490,7 +441,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.8.8" } }, "nbformat": 4, diff --git a/core/numpy/solutions/advection.py b/core/numpy/solutions/advection.py deleted file mode 100644 index efbff983b..000000000 --- a/core/numpy/solutions/advection.py +++ /dev/null @@ -1,2 +0,0 @@ -advec = (wind_vec * -grad_vec).sum(axis=-1) -print(advec.shape) diff --git a/core/numpy/solutions/broadcasting.py b/core/numpy/solutions/broadcasting.py deleted file mode 100644 index bb4a1d7d8..000000000 --- a/core/numpy/solutions/broadcasting.py +++ /dev/null @@ -1,5 +0,0 @@ -# Starting data -pressure = np.array([1000, 850, 500, 300]) -temps = np.linspace(20, 30, 24).reshape(4, 3, 2) - -temps * np.exp(pressure[:, np.newaxis, np.newaxis] / 1000) diff --git a/core/numpy/solutions/heat_index.py b/core/numpy/solutions/heat_index.py deleted file mode 100644 index bfccf3e1f..000000000 --- a/core/numpy/solutions/heat_index.py +++ /dev/null @@ -1,20 +0,0 @@ -import numpy as np - -# Here's the "data" -np.random.seed(19990503) # Make sure we all have the same data -temp = (20 * np.cos(np.linspace(0, 2 * np.pi, 100)) + - 80 + 2 * np.random.randn(100)) -rh = (np.abs(20 * np.cos(np.linspace(0, 4 * np.pi, 100)) + - 50 + 5 * np.random.randn(100))) - -# Create a mask for the two conditions described above -good_heat_index = (temp >= 80) & (rh >= 0.4) - -# Use this mask to grab the temperature and relative humidity values that together -# will give good heat index values -print(temp[good_heat_index]) - -# BONUS POINTS: Plot only the data where heat index is defined by -# inverting the mask (using ~mask) and setting invalid values to np.nan -temp[~good_heat_index] = np.nan -plt.plot(temp, 'tab:red') diff --git a/core/numpy/solutions/slice.py b/core/numpy/solutions/slice.py deleted file mode 100644 index b5155c33a..000000000 --- a/core/numpy/solutions/slice.py +++ /dev/null @@ -1,3 +0,0 @@ -data = np.array([1, 3, 5, 7, 9, 11]) -out = (data[:-1] + data[1:]) / 2 -print(out) diff --git a/core/numpy/solutions/slice_bonus.py b/core/numpy/solutions/slice_bonus.py deleted file mode 100644 index c0307f4c7..000000000 --- a/core/numpy/solutions/slice_bonus.py +++ /dev/null @@ -1,3 +0,0 @@ -data = np.array([1, 3, 5, 7, 9, 11]) -out = (data[2:] + data[1:-1] + data[:-2]) / 3 -print(out) diff --git a/core/numpy/solutions/sum_row.py b/core/numpy/solutions/sum_row.py deleted file mode 100644 index fa01c199b..000000000 --- a/core/numpy/solutions/sum_row.py +++ /dev/null @@ -1,4 +0,0 @@ -print(data[0] + data[1] + data[2]) - -# Or we can use numpy's sum and use the "axis" argument -print(np.sum(data, axis=0)) diff --git a/core/numpy/solutions/vectorized_diff.py b/core/numpy/solutions/vectorized_diff.py deleted file mode 100644 index a8c683ab5..000000000 --- a/core/numpy/solutions/vectorized_diff.py +++ /dev/null @@ -1 +0,0 @@ -2 * a[1:-1] - a[:-2] - a[2:] From d76b707d8dcc2f364d08b005c354f75847ad5a26 Mon Sep 17 00:00:00 2001 From: Drew Camron Date: Tue, 20 Apr 2021 17:20:52 -0600 Subject: [PATCH 04/15] Update TOC for new notebooks --- _toc.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/_toc.yml b/_toc.yml index cceb3f61b..20d8380b7 100644 --- a/_toc.yml +++ b/_toc.yml @@ -37,6 +37,10 @@ chapters: - file: core/overview - file: core/numpy + sections: + - file: core/numpy/numpy-basics + - file: core/numpy/numpy-intermediate + - file: core/numpy/numpy-broadcasting - file: core/matplotlib - file: core/cartopy sections: From e46d87d7792c70a3ac4ac9cbdea9339f20f50206 Mon Sep 17 00:00:00 2001 From: Drew Camron Date: Tue, 20 Apr 2021 17:21:21 -0600 Subject: [PATCH 05/15] Lint for pre-commit --- core/numpy/numpy-basics.ipynb | 6 +++--- core/numpy/numpy-broadcasting.ipynb | 14 +++++++------- core/numpy/numpy-intermediate.ipynb | 17 ++++++++--------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/core/numpy/numpy-basics.ipynb b/core/numpy/numpy-basics.ipynb index 6f521420b..87947241c 100644 --- a/core/numpy/numpy-basics.ipynb +++ b/core/numpy/numpy-basics.ipynb @@ -117,7 +117,7 @@ "outputs": [], "source": [ "# This time use a nested list of floats\n", - "a = np.array([[1., 2., 3., 4., 5.]])\n", + "a = np.array([[1.0, 2.0, 3.0, 4.0, 5.0]])\n", "a" ] }, @@ -271,7 +271,7 @@ "outputs": [], "source": [ "a = range(5, 10)\n", - "b = [3 + i * 1.5/4 for i in range(5)]" + "b = [3 + i * 1.5 / 4 for i in range(5)]" ] }, { @@ -718,7 +718,7 @@ "metadata": {}, "outputs": [], "source": [ - "data = np.arange(12).reshape(3, 4)\n" + "data = np.arange(12).reshape(3, 4)" ] }, { diff --git a/core/numpy/numpy-broadcasting.ipynb b/core/numpy/numpy-broadcasting.ipynb index 9c53c680f..8fc440f20 100644 --- a/core/numpy/numpy-broadcasting.ipynb +++ b/core/numpy/numpy-broadcasting.ipynb @@ -242,7 +242,7 @@ "metadata": {}, "outputs": [], "source": [ - "d_2d = x[:, np.newaxis]**2 + y**2" + "d_2d = x[:, np.newaxis] ** 2 + y ** 2" ] }, { @@ -260,7 +260,7 @@ "metadata": {}, "outputs": [], "source": [ - "d_3d = d_2d[..., np.newaxis] + z**2" + "d_3d = d_2d[..., np.newaxis] + z ** 2" ] }, { @@ -285,7 +285,7 @@ "metadata": {}, "outputs": [], "source": [ - "h = x[:, np.newaxis, np.newaxis]**2 + y[np.newaxis, :, np.newaxis]**2 + z**2" + "h = x[:, np.newaxis, np.newaxis] ** 2 + y[np.newaxis, :, np.newaxis] ** 2 + z ** 2" ] }, { @@ -534,7 +534,7 @@ "avg = np.zeros_like(temps)\n", "# We're just ignoring the edge effects here\n", "for i in range(1, len(temps) - 1):\n", - " sub = temps[i - 1:i + 2]\n", + " sub = temps[i - 1 : i + 2]\n", " avg[i] = sub.mean()" ] }, @@ -596,9 +596,9 @@ "block_size = 3\n", "new_shape = (len(temps) - block_size + 1, block_size)\n", "bytes_per_item = temps.dtype.itemsize\n", - "temps_strided = np.lib.stride_tricks.as_strided(temps,\n", - " shape=new_shape,\n", - " strides=(bytes_per_item, bytes_per_item))\n", + "temps_strided = np.lib.stride_tricks.as_strided(\n", + " temps, shape=new_shape, strides=(bytes_per_item, bytes_per_item)\n", + ")\n", "temps_strided" ] }, diff --git a/core/numpy/numpy-intermediate.ipynb b/core/numpy/numpy-intermediate.ipynb index e2fe8d429..890e9d6e2 100644 --- a/core/numpy/numpy-intermediate.ipynb +++ b/core/numpy/numpy-intermediate.ipynb @@ -176,10 +176,10 @@ "source": [ "# Create some synthetic data representing temperature and wind speed data\n", "np.random.seed(19990503) # Make sure we all have the same data\n", - "temp = (20 * np.cos(np.linspace(0, 2 * np.pi, 100)) +\n", - " 50 + 2 * np.random.randn(100))\n", - "spd = (np.abs(10 * np.sin(np.linspace(0, 2 * np.pi, 100)) +\n", - " 10 + 5 * np.random.randn(100)))" + "temp = 20 * np.cos(np.linspace(0, 2 * np.pi, 100)) + 50 + 2 * np.random.randn(100)\n", + "spd = np.abs(\n", + " 10 * np.sin(np.linspace(0, 2 * np.pi, 100)) + 10 + 5 * np.random.randn(100)\n", + ")" ] }, { @@ -189,6 +189,7 @@ "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", + "\n", "plt.plot(temp, 'tab:red')\n", "plt.plot(spd, 'tab:blue');" ] @@ -289,17 +290,15 @@ "source": [ "# Here's the \"data\"\n", "np.random.seed(19990503)\n", - "temp = (20 * np.cos(np.linspace(0, 2 * np.pi, 100)) +\n", - " 80 + 2 * np.random.randn(100))\n", - "rh = (np.abs(20 * np.cos(np.linspace(0, 4 * np.pi, 100)) +\n", - " 50 + 5 * np.random.randn(100)))\n", + "temp = 20 * np.cos(np.linspace(0, 2 * np.pi, 100)) + 80 + 2 * np.random.randn(100)\n", + "rh = np.abs(20 * np.cos(np.linspace(0, 4 * np.pi, 100)) + 50 + 5 * np.random.randn(100))\n", "\n", "# Create a mask for the two conditions described above\n", "good_heat_index = (temp >= 80) & (rh >= 0.4)\n", "\n", "# Use this mask to grab the temperature and relative humidity values that together\n", "# will give good heat index values\n", - "print(temp[good_heat_index]) \n", + "print(temp[good_heat_index])\n", "\n", "# BONUS POINTS: Plot only the data where heat index is defined by\n", "# inverting the mask (using ~mask) and setting invalid values to np.nan\n", From 6c86801f8ca4829a9c756a64674741318988a070 Mon Sep 17 00:00:00 2001 From: Drew Camron Date: Tue, 20 Apr 2021 17:41:42 -0600 Subject: [PATCH 06/15] Modify example code for quick nan removal --- core/numpy/numpy-intermediate.ipynb | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/core/numpy/numpy-intermediate.ipynb b/core/numpy/numpy-intermediate.ipynb index 890e9d6e2..ae4ca89bc 100644 --- a/core/numpy/numpy-intermediate.ipynb +++ b/core/numpy/numpy-intermediate.ipynb @@ -111,7 +111,8 @@ "cell_type": "code", "execution_count": null, "metadata": { - "scrolled": true + "scrolled": true, + "tags": [] }, "outputs": [], "source": [ @@ -302,8 +303,9 @@ "\n", "# BONUS POINTS: Plot only the data where heat index is defined by\n", "# inverting the mask (using ~mask) and setting invalid values to np.nan\n", - "temp[~good_heat_index] = np.nan\n", - "plt.plot(temp, 'tab:red')" + "plot_temp = temp.copy()\n", + "plot_temp[~good_heat_index] = np.nan\n", + "plt.plot(plot_temp, 'tab:red')" ] }, { @@ -403,16 +405,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "There are other numpy arg functions that return indices for operating:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "np.*arg*?" + "There are other numpy arg functions that return indices for operating; check out the [NumPy docs](https://numpy.org/doc/stable/reference/routines.sort.html) on sorting your arrays!" ] }, { From 995f0bf3c44d16d535630b89ca269e66c7e25e18 Mon Sep 17 00:00:00 2001 From: Drew Camron Date: Fri, 11 Jun 2021 09:32:18 -0600 Subject: [PATCH 07/15] Re-run template and clean metadata --- preamble/template.ipynb | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/preamble/template.ipynb b/preamble/template.ipynb index aaa806f09..6d652b79e 100644 --- a/preamble/template.ipynb +++ b/preamble/template.ipynb @@ -34,6 +34,8 @@ "metadata": {}, "source": [ "## Overview\n", + "If you have an introductory paragraph, lead with it here! Keep it short and tied to your material, then be sure to continue into the required list of topics below,\n", + "\n", "1. This is a numbered list of the specific topics\n", "1. These should map approximately to your main sections of content\n", "1. Or each second-level, `##`, header in your notebook\n", @@ -58,7 +60,7 @@ "| [Understanding of NetCDF](some-link-to-external-resource) | Helpful | Familiarity with metadata structure |\n", "| Project management | Helpful | |\n", "\n", - "- **Experience level**: with relevant packages or general self-assessed experience as **beginner/user/expert**\n", + "- **Experience level**: with relevant packages or general self-assessed experience as **beginner/intermediate/advanced**\n", "- **Time to learn**: estimate in minutes or qualitatively as **long/medium/short**\n", "- **System requirements**:\n", " - Populate with any system, version, or non-Python software requirements if necessary\n", @@ -142,11 +144,7 @@ }, { "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, + "metadata": {}, "source": [ "## Your second content section\n", "Here we can move on to our second objective, and we can demonstrate" @@ -262,7 +260,7 @@ "## Summary\n", "Add one final `---` marking the end of your body of content, and then conclude with a brief single paragraph summarizing at a high level the key pieces that were learned and how they tied to your objectives. Look to reiterate what the most important takeaways were.\n", "\n", - "### What's Next?\n", + "### What's next?\n", "Let Jupyter book tie this to the next (sequential) piece of content that people could move on to down below and in the sidebar. However, if this page uniquely enables your reader to tackle other nonsequential concepts throughout this book, or even external content, link to it here!" ] }, @@ -270,7 +268,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Resources and References\n", + "## Resources and references\n", "Finally, be rigorous in your citations and references as necessary. Give credit where credit is due. Also, feel free to link to relevant external material, further reading, documentation, etc. Then you're done! Give yourself a quick review, a high five, and send us a pull request. A few final notes:\n", " - `Kernel > Restart Kernel and Run All Cells...` to confirm that your notebook will cleanly run from start to finish\n", " - `Kernel > Restart Kernel and Clear All Outputs...` before committing your notebook, our machines will do the heavy lifting\n", @@ -284,9 +282,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python [conda env:pythia-book-dev]", + "display_name": "Python 3", "language": "python", - "name": "conda-env-pythia-book-dev-py" + "name": "python3" }, "language_info": { "codemirror_mode": { From 4291631f2d1bba1a304df45a40740d950f45565d Mon Sep 17 00:00:00 2001 From: Drew Camron Date: Fri, 11 Jun 2021 10:19:13 -0600 Subject: [PATCH 08/15] Template and content pass for basics --- core/numpy/numpy-basics.ipynb | 688 +++++++++++++++++++++------------- 1 file changed, 432 insertions(+), 256 deletions(-) diff --git a/core/numpy/numpy-basics.ipynb b/core/numpy/numpy-basics.ipynb index 87947241c..d2ebf05eb 100644 --- a/core/numpy/numpy-basics.ipynb +++ b/core/numpy/numpy-basics.ipynb @@ -4,120 +4,135 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "\"NumPy\n", "# NumPy Basics\n", - "\n", - "![NumPy Logo](https://github.com/numpy/numpy/raw/main/branding/logo/primary/numpylogo.svg \"NumPy Logo\")\n", - "\n", - "### Questions\n", - "1. What are arrays?\n", - "2. How can arrays be manipulated effectively in Python?\n", - "\n", - "### Objectives\n", - "1. Create an array of ‘data’.\n", - "2. Perform basic calculations on this data using python math functions.\n", - "3. Slice and index the array" + "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ + "## Overview\n", "NumPy is the fundamental package for scientific computing with Python. It contains among other things:\n", + "\n", "- a powerful N-dimensional array object\n", "- sophisticated (broadcasting) functions\n", "- useful linear algebra, Fourier transform, and random number capabilities\n", "\n", - "The NumPy array object is the common interface for working with typed arrays of data across a wide-variety of scientific Python packages. NumPy also features a C-API, which enables interfacing existing Fortran/C/C++ libraries with Python and NumPy." + "The NumPy array object is the common interface for working with typed arrays of data across a wide-variety of scientific Python packages. NumPy also features a C-API, which enables interfacing existing Fortran/C/C++ libraries with Python and NumPy. In this notebook we will cover\n", + "\n", + "1. Creating an `array`\n", + "1. Math and calculations with arrays\n", + "1. Inspecting an array with slicing and indexing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Create an array of 'data'\n", + "## Prerequisites\n", "\n", - "The NumPy array represents a *contiguous* block of memory, holding entries of a given type (and hence fixed size). The entries are laid out in memory according to the shape, or list of dimension sizes." + "| Concepts | Importance | Notes |\n", + "| --- | --- | --- |\n", + "| [Python Quickstart](../../foundations/quickstart) | Necessary | Lists, indexing, slicing, math |\n", + "\n", + "* **Experience level**: beginner\n", + "* **Time to learn**: medium\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Imports\n", + "A common convention you might encounter is to rename `numpy` to `np` on import to shorten it for the many times we will be calling on `numpy` for functionality." ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, + "metadata": {}, "outputs": [], "source": [ - "# Convention for import to get shortened namespace\n", "import numpy as np" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an array of 'data'\n", + "\n", + "The NumPy array represents a *contiguous* block of memory, holding entries of a given type (and hence fixed size). The entries are laid out in memory according to the shape, or list of dimension sizes. Let's start by creating an array from a list of integers and taking a look at it," + ] + }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ - "# Create a simple array from a list of integers\n", "a = np.array([1, 2, 3])\n", "a" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can inspect the number of dimensions our array is organized along with `ndim`, and how long each of these dimensions are with `shape`" + ] + }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "# See how many dimensions the array has\n", "a.ndim" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ - "# Print out the shape attribute\n", "a.shape" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So our 1-dimensional array has a shape of `3` along that dimension! Finally we can check out the underlying type of our underlying data," + ] + }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ - "# Print out the data type attribute\n", "a.dtype" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's expand this with a new data type, and by using a list of lists we can grow the dimensions of our array!" + ] + }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, + "metadata": {}, "outputs": [], "source": [ - "# This time use a nested list of floats\n", - "a = np.array([[1.0, 2.0, 3.0, 4.0, 5.0]])\n", + "a = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])\n", "a" ] }, @@ -127,49 +142,42 @@ "metadata": {}, "outputs": [], "source": [ - "# See how many dimensions the array has\n", "a.ndim" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ - "# Print out the shape attribute\n", "a.shape" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ - "# Print out the data type attribute\n", "a.dtype" ] }, { "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, + "metadata": {}, + "source": [ + "And as before we can use `ndim`, `shape`, and `dtype` to discover how many dimensions of what lengths are making up our array of floats." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "NumPy also provides helper functions for generating arrays of data to save you typing for regularly spaced data. \n", + "### Generation\n", + "NumPy also provides helper functions for generating arrays of data to save you typing for regularly spaced data. Don't forget your Python indexing rules!\n", "\n", - "* `arange(start, stop, interval)` creates a range of values in the interval `[start,stop)` with `step` spacing.\n", + "* `arange(start, stop, step)` creates a range of values in the interval `[start,stop)` with `step` spacing.\n", "* `linspace(start, stop, num)` creates a range of `num` evenly spaced values over the range `[start,stop]`." ] }, @@ -177,21 +185,17 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### arange" + "#### arange" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ "a = np.arange(5)\n", - "print(a)" + "a" ] }, { @@ -201,42 +205,53 @@ "outputs": [], "source": [ "a = np.arange(3, 11)\n", - "print(a)" + "a" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ "a = np.arange(1, 10, 2)\n", - "print(a)" + "a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### linspace" + "#### linspace" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, + "outputs": [], + "source": [ + "b = np.linspace(0, 4, 5)\n", + "b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ - "b = np.linspace(5, 15, 5)\n", - "print(b)" + "b.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b = np.linspace(3, 10, 15)\n", + "b" ] }, { @@ -246,20 +261,26 @@ "outputs": [], "source": [ "b = np.linspace(2.5, 10.25, 11)\n", - "print(b)" + "b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b = np.linspace(0, 100, 30)\n", + "b" ] }, { "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, + "metadata": {}, "source": [ - "## Perform basic calculations with Python\n", + "## Perform calculations with NumPy\n", "\n", - "### Basic math\n", + "### Arithmetic\n", "\n", "In core Python, that is *without* NumPy, creating sequences of values and adding them together requires writing a lot of manual loops, just like one would do in C/C++:" ] @@ -270,18 +291,16 @@ "metadata": {}, "outputs": [], "source": [ - "a = range(5, 10)\n", - "b = [3 + i * 1.5 / 4 for i in range(5)]" + "a = list(range(5, 10))\n", + "b = [3 + i * 1.5 / 4 for i in range(5)]\n", + "\n", + "a, b" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ "result = []\n", @@ -292,11 +311,7 @@ }, { "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, + "metadata": {}, "source": [ "That is very verbose and not very intuitive. Using NumPy this becomes:" ] @@ -314,11 +329,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ "a + b" @@ -328,16 +339,63 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The four major mathematical operations operate in the same way. They perform an element-by-element calculation of the two arrays. The two must be the same shape though!" + "Many major mathematical operations operate in the same way. They perform an element-by-element calculation of the two arrays." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a - b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a / b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a ** b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "

Warning

\n", + " These arrays must be the same shape!\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b = np.linspace(3, 4.5, 6)\n", + "a.shape, b.shape" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "slideshow": { - "slide_type": "fragment" - } + "tags": [ + "raises-exception" + ] }, "outputs": [], "source": [ @@ -346,11 +404,7 @@ }, { "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, + "metadata": {}, "source": [ "### Constants\n", "\n", @@ -375,43 +429,49 @@ "np.e" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can use these for classic calculations you might be familiar with! Here we can create a range `t = [0, 2 pi]` by `pi/4`," + ] + }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ - "# This makes working with radians effortless!\n", "t = np.arange(0, 2 * np.pi + np.pi / 4, np.pi / 4)\n", "t" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "t / np.pi" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Array math functions\n", "\n", - "NumPy also has math functions that can operate on arrays. Similar to the math operations, these greatly simplify and speed up these operations. Be sure to checkout the [listing](https://docs.scipy.org/doc/numpy/reference/routines.math.html) of mathematical functions in the NumPy documentation." + "NumPy also has math functions that can operate on arrays. Similar to the math operations, these greatly simplify and speed up these operations. Let's start with calculating $\\sin(t)$!" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ - "# Calculate the sine function\n", "sin_t = np.sin(t)\n", - "print(sin_t)" + "sin_t" ] }, { @@ -420,8 +480,7 @@ "metadata": {}, "outputs": [], "source": [ - "# Round to three decimal places\n", - "print(np.round(sin_t, 3))" + "np.round(sin_t, 3)" ] }, { @@ -430,9 +489,25 @@ "metadata": {}, "outputs": [], "source": [ - "# Calculate the cosine function\n", "cos_t = np.cos(t)\n", - "print(cos_t)" + "cos_t" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "

Info

\n", + " Check out NumPy's list of mathematical functions here!\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can convert between degrees and radians with only NumPy." ] }, { @@ -441,9 +516,15 @@ "metadata": {}, "outputs": [], "source": [ - "# Convert radians to degrees\n", "degrees = np.rad2deg(t)\n", - "print(degrees)" + "degrees" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We are similarly provided algorithms for operations including integration, bulk summing, and cumulative summing." ] }, { @@ -452,9 +533,8 @@ "metadata": {}, "outputs": [], "source": [ - "# Integrate the sine function with the trapezoidal rule\n", "sine_integral = np.trapz(sin_t, t)\n", - "print(np.round(sine_integral, 3))" + "np.round(sine_integral, 3)" ] }, { @@ -463,9 +543,8 @@ "metadata": {}, "outputs": [], "source": [ - "# Sum the values of the cosine\n", "cos_sum = np.sum(cos_t)\n", - "print(cos_sum)" + "cos_sum" ] }, { @@ -474,60 +553,88 @@ "metadata": {}, "outputs": [], "source": [ - "# Calculate the cumulative sum of the cosine\n", "cos_csum = np.cumsum(cos_t)\n", "print(cos_csum)" ] }, { "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, + "metadata": {}, "source": [ - "## Index and slice arrays\n", + "## Indexing and subsetting arrays\n", "\n", - "Indexing is how we pull individual data items out of an array. Slicing extends this process to pulling out a regular set of the items." + "### Indexing\n", + "\n", + "We can use integer indexing to reach into our arrays and pull out individual elements. Let's make a toy 2-d array to explore," ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, + "metadata": {}, "outputs": [], "source": [ - "# Create an array for testing\n", "a = np.arange(12).reshape(3, 4)\n", "a" ] }, { "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, + "metadata": {}, + "source": [ + "Recall that Python indexing starts at `0`, and we can begin indexing our array with the list-style `list[element]` notation," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "to pull out just our first _row_ of data within `a`. Similarly we can index in reverse with negative indices," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[-1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "to pull out just the last row of data within `a`. This notation extends to as many dimensions as make up our array as `array[m, n, p, ...]`. The following diagram shows these indices for an example, 2-dimensional `6x6` array," + ] + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "Indexing in Python is 0-based, so the command below looks for the 2nd item along the first dimension (row) and the 3rd along the second dimension (column).\n", - "\n", "![](array_index.png)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For example, let's find the entry in our array corresponding to the 2nd row (`m=1` in Python) and the 3rd column (`n=2` in Python)" + ] + }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ "a[1, 2]" @@ -535,110 +642,99 @@ }, { "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, + "metadata": {}, "source": [ - "Can also just index on one dimension" + "We can again use these negative indices to index backwards," ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ - "a[2]" + "a[-1, -1]" ] }, { "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, + "metadata": {}, "source": [ - "Negative indices are also allowed, which permit indexing relative to the end of the array." + "and even mix-and-match along dimensions," ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ - "a[0, -1]" + "a[1, -2]" ] }, { "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, + "metadata": {}, "source": [ - "Slicing syntax is written as `start:stop[:step]`, where all numbers are optional.\n", + "### Slices\n", + "\n", + "Slicing syntax is written as `array[start:stop[:step]]`, where **all numbers are optional**.\n", "- defaults: \n", " - start = 0\n", " - stop = len(dim)\n", " - step = 1\n", - "- The second colon is also optional if no step is used.\n", + "- The second colon is **also optional** if no step is used.\n", "\n", - "It should be noted that end represents one past the last item; one can also think of it as a half open interval: `[start, end)`" + "Let's pull out just the first row, `m=0` of `a` and see how this works!" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, + "metadata": {}, "outputs": [], "source": [ - "# Get the 2nd and 3rd rows\n", - "a[1:3]" + "b = a[0]\n", + "b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Laying out our default slice to see the entire array explicitly looks something like this," ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ - "# All rows and 3rd column\n", - "a[:, 2]" + "b[0:4:1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "where again, these default values are optional," ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, + "metadata": {}, "outputs": [], "source": [ - "# ... can be used to replace one or more full slices\n", - "a[..., 2]" + "b[::]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and even the second `:` is optional" ] }, { @@ -647,15 +743,14 @@ "metadata": {}, "outputs": [], "source": [ - "# Slice every other row\n", - "a[::2]" + "b[:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The code below calculates a two point average using a Python list and loop, and we can then convert it to obtain the same results using NumPy slicing." + "Now to actually make our own slice, let's select select all elements from `m=0` to `m=2`" ] }, { @@ -664,16 +759,40 @@ "metadata": {}, "outputs": [], "source": [ - "data = [1, 3, 5, 7, 9, 11]\n", - "out = []\n", - "\n", - "# Look carefully at the loop. Think carefully about the sequence of values\n", - "# that data[i] takes--is there some way to get those values as a numpy slice?\n", - "# What about for data[i + 1]?\n", - "for i in range(len(data) - 1):\n", - " out.append((data[i] + data[i + 1]) / 2)\n", - "\n", - "print(out)" + "b[0:2]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "

Warning

\n", + " Slice notation is exclusive of the final index.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This means that slices will include ever value **up to** your `stop` index and not this index itself, like a half-open interval `[start, end)`. For example," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b[3]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "reveals a different value than" ] }, { @@ -682,16 +801,23 @@ "metadata": {}, "outputs": [], "source": [ - "data = np.array([1, 3, 5, 7, 9, 11])\n", - "out = (data[:-1] + data[1:]) / 2\n", - "print(out)" + "b[0:3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Can we extend the NumPy version to do a 3 point (running) average? Of course!" + "Finally, a few more examples of this notation before reintroducing our 2-d array `a`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b[2:] # m=2 through the end, can leave off the number" ] }, { @@ -700,16 +826,14 @@ "metadata": {}, "outputs": [], "source": [ - "data = np.array([1, 3, 5, 7, 9, 11])\n", - "out = (data[2:] + data[1:-1] + data[:-2]) / 3\n", - "print(out)" + "b[:3] # similarly, the same as our b[0:3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Given the array of data below, we can calculate the total of each of the columns (i.e. add each of the three rows together):" + "This entire syntax can be extended to each dimension of multidimensional arrays." ] }, { @@ -718,7 +842,7 @@ "metadata": {}, "outputs": [], "source": [ - "data = np.arange(12).reshape(3, 4)" + "a" ] }, { @@ -727,7 +851,7 @@ "metadata": {}, "outputs": [], "source": [ - "print(data[0] + data[1] + data[2])" + "a[0:2, :]" ] }, { @@ -736,26 +860,78 @@ "metadata": {}, "outputs": [], "source": [ - "# Or we can use numpy's sum and use the \"axis\" argument\n", - "print(np.sum(data, axis=0))" + "a[:, 2]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[:, ::2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Resources\n", + "For any shape of array, you can use `...` to capture full slices of every un-specific dimension." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "c = a.reshape(2, 2, 3)\n", + "c" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "c[0, ...]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "c[..., -1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Summary\n", + "In this notebook we introduced NumPy and the `ndarray` that is so crucial to the entirety of the scientific Python community ecosystem. We created some arrays, used some of NumPy's own mathematical functions to manipulate them, and then introduced the world of NumPy indexing and selecting for even multi-dimensional arrays.\n", "\n", - "- [NumPy User Guide](http://docs.scipy.org/doc/numpy/user/)\n", - "- [SciPy Lecture Notes](https://scipy-lectures.org/)" + "### What's next?\n", + "This notebook is the gateway to nearly every other Pythia resource here. This information is crucial for understanding SciPy, pandas, xarray, and more. Continue into NumPy to explore some more intermediate and advanced topics!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Top\n", - "
" + "## Resources and references\n", + "- [NumPy User Guide](http://docs.scipy.org/doc/numpy/user/)\n", + "- [SciPy Lecture Notes](https://scipy-lectures.org/)" ] } ], @@ -775,7 +951,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.8.10" } }, "nbformat": 4, From 092a2c74a6ff455b0eff9f2f1081d9178506489e Mon Sep 17 00:00:00 2001 From: Drew Camron Date: Mon, 14 Jun 2021 15:07:14 -0600 Subject: [PATCH 09/15] Template and content pass for intermediate --- core/numpy/intermediate-numpy.ipynb | 674 ++++++++++++++++++++++++++++ core/numpy/numpy-intermediate.ipynb | 441 ------------------ 2 files changed, 674 insertions(+), 441 deletions(-) create mode 100644 core/numpy/intermediate-numpy.ipynb delete mode 100644 core/numpy/numpy-intermediate.ipynb diff --git a/core/numpy/intermediate-numpy.ipynb b/core/numpy/intermediate-numpy.ipynb new file mode 100644 index 000000000..a01c42fe7 --- /dev/null +++ b/core/numpy/intermediate-numpy.ipynb @@ -0,0 +1,674 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"NumPy\n", + "# Intermediate NumPy\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "1. Working with multiple dimensions\n", + "1. Subsetting of irregular arrays with booleans\n", + "1. Sorting, or indexing with indices" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "| Concepts | Importance | Notes |\n", + "| --- | --- | --- |\n", + "| [NumPy Basics](numpy-basics) | Necessary | |\n", + "\n", + "* **Experience level**: user\n", + "* **Time to learn**: medium\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Imports\n", + "We will be including matplotlib to illustrate some of our examples, but you don't need knowledge of it to complete this notebook." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using axes to slice arrays\n", + "\n", + "The solution to the last exercise in the Numpy Basics notebook introduces an important concept when working with NumPy: the axis. This indicates the particular dimension along which a function should operate (provided the function does something taking multiple values and converts to a single value). \n", + "\n", + "Let's look at a concrete example with `sum`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = np.arange(12).reshape(3, 4)\n", + "a" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This calculates the total of all values in the array" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.sum(a)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "

Info

\n", + " Some of NumPy's functions can be accessed as `ndarray` methods!\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a.sum()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, with a reminder about how our array is shaped," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "we can specify `axis` to get _just_ the sum across each of our rows." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.sum(a, axis=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or do the same and take the some across columns:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.sum(a, axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After putting together some data and introducing some more advanced calculations, let's demonstrate a multi-layered example: calculating temperature advection. If you're not familiar with this (don't worry!), we'll be looking to calculate\n", + "\n", + "\\begin{equation*}\n", + "\\text{advection} = -\\vec{v} \\cdot \\nabla T\n", + "\\end{equation*}\n", + "\n", + "and to do so we'll start with some random $T$ and $\\vec{v}$ values," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temp = np.random.randn(100, 50)\n", + "u = np.random.randn(100, 50)\n", + "v = np.random.randn(100, 50)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can calculate the `np.gradient` of our new $T(100x50)$ field as two separate component gradients," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "gradient_x, gradient_y = np.gradient(temp)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to calculate $-\\vec{v} \\cdot \\nabla T$, we will use `np.dstack` to turn our two separate component gradient fields into one multidimensional field containing $x$ and $y$ gradients at each of our $100x50$ points," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "grad_vectors = np.dstack([gradient_x, gradient_y])\n", + "print(grad_vectors.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and then do the same for our separate $u$ and $v$ wind components," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "wind_vectors = np.dstack([u, v])\n", + "print(wind_vectors.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we can calculate the dot product of these two multidimensional fields of wind and temperature gradient components by hand as an element-wise multiplication, `*`, and then a `sum` of our separate components at each point," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "advection = (wind_vectors * -grad_vectors).sum(axis=-1)\n", + "print(advection.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Indexing arrays with boolean values\n", + "Numpy can easily create arrays of boolean values and use those to select certain values to extract from an array" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create some synthetic data representing temperature and wind speed data\n", + "np.random.seed(19990503) # Make sure we all have the same data\n", + "temp = 20 * np.cos(np.linspace(0, 2 * np.pi, 100)) + 50 + 2 * np.random.randn(100)\n", + "speed = np.abs(\n", + " 10 * np.sin(np.linspace(0, 2 * np.pi, 100)) + 10 + 5 * np.random.randn(100)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(temp, 'tab:red')\n", + "plt.plot(speed, 'tab:blue');" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By doing a comparision between a NumPy array and a value, we get an\n", + "array of values representing the results of the comparison between\n", + "each element and the value" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temp > 45" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This, which is its own NumPy array of `boolean` values, can be used as an index to another array of the same size. We can even use it as an index within the original `temp` array we used to compare," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temp[temp > 45]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "

Info

\n", + " This only returns the values from our original array meeting the indexing conditions, nothing more! Note the size,\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temp[temp > 45].shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "

Warning

\n", + " Indexing arrays with arrays requires them to be the same size!\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we store this array somewhere new," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temp_45 = temp[temp > 45]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "raises-exception" + ] + }, + "outputs": [], + "source": [ + "temp_45[temp < 45]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We find that our original `(100,)` shape array is too large to subset our new `(60,)` array." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If their sizes _do_ match, the boolean array can come from a totally different array!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "speed > 10" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temp[speed > 10]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To extend this, we can use this conditional indexing to _assign_ new values to certain positions within our array, somewhat like a masking operation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Make a copy so we don't modify the original data\n", + "temp2 = temp.copy()\n", + "speed2 = speed.copy()\n", + "\n", + "# Replace all places where speed is <10 with NaN (not a number)\n", + "temp2[speed < 10] = np.nan\n", + "speed2[speed < 10] = np.nan" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(temp2, 'tab:red');" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and to put this in context," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(temp, 'r:')\n", + "plt.plot(temp2, 'r')\n", + "plt.plot(speed, 'b:')\n", + "plt.plot(speed2, 'b');" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we use parentheses to preserve the order of operations, we can combine these conditions with other bitwise operators like the `&` for `bitwise_and`," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "multi_mask = (temp < 45) & (speed > 10)\n", + "multi_mask" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temp[multi_mask]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Heat index is only defined for temperatures >= 80F and relative humidity values >= 40%. Using the data generated below, we can use boolean indexing to extract the data where heat index has a valid value." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Here's the \"data\"\n", + "np.random.seed(19990503)\n", + "temp = 20 * np.cos(np.linspace(0, 2 * np.pi, 100)) + 80 + 2 * np.random.randn(100)\n", + "relative_humidity = np.abs(\n", + " 20 * np.cos(np.linspace(0, 4 * np.pi, 100)) + 50 + 5 * np.random.randn(100)\n", + ")\n", + "\n", + "# Create a mask for the two conditions described above\n", + "good_heat_index = (temp >= 80) & (relative_humidity >= 0.4)\n", + "\n", + "# Use this mask to grab the temperature and relative humidity values that together\n", + "# will give good heat index values\n", + "print(temp[good_heat_index])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another bitwise operator we can find helpful is Python's `~` complement operator, which can give us the **inverse** of our specific mask to let us assign `np.nan` to every value _not_ satisfied in `good_heat_index`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plot_temp = temp.copy()\n", + "plot_temp[~good_heat_index] = np.nan\n", + "plt.plot(plot_temp, 'tab:red');" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Indexing using arrays of indices\n", + "\n", + "You can also use a list or array of indices to extract particular values--this is a natural extension of the regular indexing. For instance, just as we can select the first element:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temp[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also extract the first, fifth, and tenth elements as a list:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temp[[0, 4, 9]]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One of the ways this comes into play is trying to sort numpy arrays using `argsort`. This function returns the indices of the array that give the items in sorted order. So for our `temp`," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "inds = np.argsort(temp)\n", + "inds" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "i.e., our lowest value is at index `52`, next `47`, and so on. We can use this array of indices as an index for `temp`," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "temp[inds]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "to get a sorted array back!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With some clever slicing, we can pull out the last 10, or 10 highest, values of `temp`," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ten_highest = inds[-10:]\n", + "print(temp[ten_highest])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are other numpy arg functions that return indices for operating; check out the [NumPy docs](https://numpy.org/doc/stable/reference/routines.sort.html) on sorting your arrays!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Summary\n", + "In this notebook we introduced the power of understanding the dimensions of our data by specifying math along `axis`, used `True` and `False` values to subset our data according to conditions, and used lists of positions within our array to sort our data.\n", + "\n", + "### What's Next\n", + "Taking some time to practice this is valuable to be able to quickly manipulate arrays of information in useful or scientific ways." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Resources and references\n", + "The [NumPy Users Guide](https://numpy.org/devdocs/user/quickstart.html#less-basic) expands further on some of these topics, as well as suggests various [Tutorials](https://numpy.org/learn/), lectures, and more at this stage." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/core/numpy/numpy-intermediate.ipynb b/core/numpy/numpy-intermediate.ipynb deleted file mode 100644 index ae4ca89bc..000000000 --- a/core/numpy/numpy-intermediate.ipynb +++ /dev/null @@ -1,441 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Intermediate NumPy\n", - "\n", - "![NumPy Logo](https://github.com/numpy/numpy/raw/main/branding/logo/primary/numpylogo.svg \"NumPy Logo\")\n", - "\n", - "### Questions\n", - "1. How do we work with the multiple dimensions in a NumPy Array?\n", - "1. How can we extract irregular subsets of data?\n", - "1. How can we sort an array?\n", - "\n", - "### Objectives\n", - "1. Using axes to slice arrays\n", - "1. Index arrays using true and false\n", - "1. Index arrays using arrays of indices" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "\n", - "## 1. Using axes to slice arrays\n", - "\n", - "The solution to the last exercise in the Numpy Basics notebook introduces an important concept when working with NumPy: the axis. This indicates the particular dimension along which a function should operate (provided the function does something taking multiple values and converts to a single value). \n", - "\n", - "Let's look at a concrete example with `sum`:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Convention for import to get shortened namespace\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [], - "source": [ - "# Create an array for testing\n", - "a = np.arange(12).reshape(3, 4)\n", - "a" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# This calculates the total of all values in the array\n", - "np.sum(a)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Keep this in mind:\n", - "a.shape" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Instead, take the sum across the rows:\n", - "np.sum(a, axis=0)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Or do the same and take the some across columns:\n", - "np.sum(a, axis=1)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "After putting together some data and introducing some more advanced calculations, let's demonstrate a multi-layered example: calculating advection." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true, - "tags": [] - }, - "outputs": [], - "source": [ - "# Synthetic data\n", - "temp = np.random.randn(100, 50)\n", - "u = np.random.randn(100, 50)\n", - "v = np.random.randn(100, 50)\n", - "\n", - "# Calculate the gradient components\n", - "gradx, grady = np.gradient(temp)\n", - "\n", - "# Turn into an array of vectors:\n", - "# axis 0 is x position\n", - "# axis 1 is y position\n", - "# axis 2 is the vector components\n", - "grad_vec = np.dstack([gradx, grady])\n", - "print(grad_vec.shape)\n", - "\n", - "# Turn wind components into vector\n", - "wind_vec = np.dstack([u, v])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Moving on to calculate advection, the dot product of wind and the negative of gradient, we multiply and add by hand." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "advec = (wind_vec * -grad_vec).sum(axis=-1)\n", - "print(advec.shape)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Top\n", - "
" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "## 2. Indexing Arrays with Boolean Values\n", - "Numpy can easily create arrays of boolean values and use those to select certain values to extract from an array" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Create some synthetic data representing temperature and wind speed data\n", - "np.random.seed(19990503) # Make sure we all have the same data\n", - "temp = 20 * np.cos(np.linspace(0, 2 * np.pi, 100)) + 50 + 2 * np.random.randn(100)\n", - "spd = np.abs(\n", - " 10 * np.sin(np.linspace(0, 2 * np.pi, 100)) + 10 + 5 * np.random.randn(100)\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "plt.plot(temp, 'tab:red')\n", - "plt.plot(spd, 'tab:blue');" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "By doing a comparision between a NumPy array and a value, we get an\n", - "array of values representing the results of the comparison between\n", - "each element and the value" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "temp > 45" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can take the resulting array and use this to index into the\n", - "NumPy array and retrieve the values where the result was true" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(temp[temp > 45])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "So long as the size of the boolean array matches the data, the boolean array can come from anywhere" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(temp[spd > 10])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Make a copy so we don't modify the original data\n", - "temp2 = temp.copy()\n", - "\n", - "# Replace all places where spd is <10 with NaN (not a number) so matplotlib skips it\n", - "temp2[spd < 10] = np.nan\n", - "plt.plot(temp2, 'tab:red')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Can also combine multiple boolean arrays using the syntax for bitwise operations. **MUST HAVE PARENTHESES** due to operator precedence." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(temp[(temp < 45) & (spd > 10)])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Heat index is only defined for temperatures >= 80F and relative humidity values >= 40%. Using the data generated below, we can use boolean indexing to extract the data where heat index has a valid value." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Here's the \"data\"\n", - "np.random.seed(19990503)\n", - "temp = 20 * np.cos(np.linspace(0, 2 * np.pi, 100)) + 80 + 2 * np.random.randn(100)\n", - "rh = np.abs(20 * np.cos(np.linspace(0, 4 * np.pi, 100)) + 50 + 5 * np.random.randn(100))\n", - "\n", - "# Create a mask for the two conditions described above\n", - "good_heat_index = (temp >= 80) & (rh >= 0.4)\n", - "\n", - "# Use this mask to grab the temperature and relative humidity values that together\n", - "# will give good heat index values\n", - "print(temp[good_heat_index])\n", - "\n", - "# BONUS POINTS: Plot only the data where heat index is defined by\n", - "# inverting the mask (using ~mask) and setting invalid values to np.nan\n", - "plot_temp = temp.copy()\n", - "plot_temp[~good_heat_index] = np.nan\n", - "plt.plot(plot_temp, 'tab:red')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Top\n", - "
" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "## 3. Indexing using arrays of indices\n", - "\n", - "You can also use a list or array of indices to extract particular values--this is a natural extension of the regular indexing. For instance, just as we can select the first element:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(temp[0])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can also extract the first, fifth, and tenth elements:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(temp[[0, 4, 9]])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "One of the ways this comes into play is trying to sort numpy arrays using `argsort`. This function returns the indices of the array that give the items in sorted order. So for our temp \"data\":" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "inds = np.argsort(temp)\n", - "print(inds)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can use this array of indices to pass into temp to get it in sorted order:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(temp[inds])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Or we can slice `inds` to only give the 10 highest temperatures:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ten_highest = inds[-10:]\n", - "print(temp[ten_highest])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are other numpy arg functions that return indices for operating; check out the [NumPy docs](https://numpy.org/doc/stable/reference/routines.sort.html) on sorting your arrays!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Top\n", - "
" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} From 660a5086c3d65a9565e07d0a9f0811397f880b42 Mon Sep 17 00:00:00 2001 From: Drew Camron Date: Mon, 14 Jun 2021 15:33:00 -0600 Subject: [PATCH 10/15] Template and content pass (yow) for broadcasting --- core/numpy/numpy-broadcasting.ipynb | 134 +++++++++++++++++++++------- 1 file changed, 104 insertions(+), 30 deletions(-) diff --git a/core/numpy/numpy-broadcasting.ipynb b/core/numpy/numpy-broadcasting.ipynb index 8fc440f20..b8bd5124d 100644 --- a/core/numpy/numpy-broadcasting.ipynb +++ b/core/numpy/numpy-broadcasting.ipynb @@ -4,25 +4,59 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# NumPy Broadcasting and Vectorization\n", - "\n", - "![NumPy Logo](https://github.com/numpy/numpy/raw/main/branding/logo/primary/numpylogo.svg \"NumPy Logo\")\n", + "\"NumPy\n", + "# NumPy Broadcasting\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "1. Working with multiple dimensions\n", + "1. Subsetting of irregular arrays with booleans\n", + "1. Sorting, or indexing with indices" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", "\n", - "### Questions\n", - "1. How can we work with arrays of differing shapes without needing to manually loop or copy data?\n", - "1. How can we reframe operations on data to avoid looping in Python?\n", + "| Concepts | Importance | Notes |\n", + "| --- | --- | --- |\n", + "| [NumPy Basics](numpy-basics) | Necessary | |\n", + "| [Intermediate NumPy](intermediate-numpy) | Helpful | |\n", + "| [Conceptual guide to broadcasting](https://numpy.org/doc/stable/user/theory.broadcasting.html#array-broadcasting-in-numpy) | Helpful | |\n", "\n", - "### Objectives\n", - "1. Use broadcasting to implicitly loop over data\n", - "1. Vectorize calculations to avoid explicit loops" + "* **Experience level**: advanced\n", + "* **Time to learn**: medium\n", + "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "## 1. Using broadcasting to implicitly loop over data" + "## Imports" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using broadcasting to implicitly loop over data" ] }, { @@ -65,11 +99,27 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This takes the single element in `b` and adds it to each of the elements in `a`. This won't work for just any `b`, though; for instance, the following:\n", - "```python\n", + "This takes the single element in `b` and adds it to each of the elements in `a`. This won't work for just any `b`, though; for instance, the following:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "raises-exception" + ] + }, + "outputs": [], + "source": [ "b = np.array([5, 6, 7])\n", - "a + b\n", - "```\n", + "a + b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "won't work. It does work if `a` and `b` are the same shape:" ] }, @@ -202,6 +252,15 @@ "a + bb" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "(a + bb).shape" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -304,6 +363,13 @@ "h.shape" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and we can confirm that the results here are identical," + ] + }, { "cell_type": "code", "execution_count": null, @@ -333,10 +399,9 @@ "metadata": {}, "outputs": [], "source": [ - "# Starting data\n", "pressure = np.array([1000, 850, 500, 300])\n", "temps = np.linspace(20, 30, 24).reshape(4, 3, 2)\n", - "print(temps.shape)" + "pressure.shape, temps.shape" ] }, { @@ -345,23 +410,23 @@ "metadata": {}, "outputs": [], "source": [ - "temps * np.exp(pressure[:, np.newaxis, np.newaxis] / 1000)" + "pressure[:, np.newaxis, np.newaxis].shape" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ - "Top\n", - "
" + "temps * np.exp(pressure[:, np.newaxis, np.newaxis] / 1000)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "## 2. Vectorize calculations to avoid explicit loops" + "## Vectorize calculations to avoid explicit loops" ] }, { @@ -532,7 +597,6 @@ "outputs": [], "source": [ "avg = np.zeros_like(temps)\n", - "# We're just ignoring the edge effects here\n", "for i in range(1, len(temps) - 1):\n", " sub = temps[i - 1 : i + 2]\n", " avg[i] = sub.mean()" @@ -802,17 +866,27 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Resources\n", - "* [NumPy Broadcasting Documentation](https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html)\n", - "* [NumPy Broadcasting Article](https://numpy.org/devdocs/user/theory.broadcasting.html)" + "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Top\n", - "
" + "## Summary\n", + "We've previewed some advanced NumPy capabilities with a focus on _vectorization_, or using clever broadcasting and windows of our data to enhance the speed and readability of our calculations. Doing so can reduce explicit construction of loops in your code and keep calculations running quickly!\n", + "\n", + "### What's next\n", + "This is an advanced NumPy topic, and important to designing your own calculations in a way for them to be as scalable and quick as possible. Please check out some of the following links to explore this topic further." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Resources and references\n", + "* [NumPy Broadcasting Documentation](https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html)\n", + "* [NumPy Broadcasting Article](https://numpy.org/devdocs/user/theory.broadcasting.html)" ] } ], @@ -832,7 +906,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.8.10" } }, "nbformat": 4, From 2b618e9f519ff055fc5d849df3894dbedc411378 Mon Sep 17 00:00:00 2001 From: Drew Camron Date: Fri, 11 Jun 2021 10:36:51 -0600 Subject: [PATCH 11/15] Remove empty last cell --- foundations/quickstart.ipynb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/foundations/quickstart.ipynb b/foundations/quickstart.ipynb index 56c9673c6..356529a27 100644 --- a/foundations/quickstart.ipynb +++ b/foundations/quickstart.ipynb @@ -617,14 +617,6 @@ "\n", "Read on for more details on how to install and run Python and necessary packages on your own laptop." ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "67c42944", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { From 12d57b95c71f181bda0482dadee7ff83bbd1aef9 Mon Sep 17 00:00:00 2001 From: Drew Camron Date: Mon, 14 Jun 2021 15:46:57 -0600 Subject: [PATCH 12/15] Rename numpy-intermediate in toc --- _toc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_toc.yml b/_toc.yml index 20d8380b7..cc2111f3a 100644 --- a/_toc.yml +++ b/_toc.yml @@ -39,7 +39,7 @@ - file: core/numpy sections: - file: core/numpy/numpy-basics - - file: core/numpy/numpy-intermediate + - file: core/numpy/intermediate-numpy - file: core/numpy/numpy-broadcasting - file: core/matplotlib - file: core/cartopy From 2762df062a63499a4b537bf8778a2a71840a6ea5 Mon Sep 17 00:00:00 2001 From: Drew Camron Date: Mon, 14 Jun 2021 16:37:26 -0600 Subject: [PATCH 13/15] Spelling/grammar and response to reviews --- core/numpy/intermediate-numpy.ipynb | 12 +++--- core/numpy/numpy-basics.ipynb | 20 +++++++++- core/numpy/numpy-broadcasting.ipynb | 61 ++++++++++++++++------------- 3 files changed, 58 insertions(+), 35 deletions(-) diff --git a/core/numpy/intermediate-numpy.ipynb b/core/numpy/intermediate-numpy.ipynb index a01c42fe7..c550480be 100644 --- a/core/numpy/intermediate-numpy.ipynb +++ b/core/numpy/intermediate-numpy.ipynb @@ -39,7 +39,7 @@ "metadata": {}, "source": [ "## Imports\n", - "We will be including matplotlib to illustrate some of our examples, but you don't need knowledge of it to complete this notebook." + "We will be including [matplotlib](../matplotlib) to illustrate some of our examples, but you don't need knowledge of it to complete this notebook." ] }, { @@ -144,7 +144,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Or do the same and take the some across columns:" + "Or do the same and take the sum across columns:" ] }, { @@ -252,7 +252,7 @@ "metadata": {}, "source": [ "## Indexing arrays with boolean values\n", - "Numpy can easily create arrays of boolean values and use those to select certain values to extract from an array" + "NumPy can easily create arrays of boolean values and use those to select certain values to extract from an array" ] }, { @@ -283,7 +283,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "By doing a comparision between a NumPy array and a value, we get an\n", + "By doing a comparison between a NumPy array and a value, we get an\n", "array of values representing the results of the comparison between\n", "each element and the value" ] @@ -563,7 +563,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "One of the ways this comes into play is trying to sort numpy arrays using `argsort`. This function returns the indices of the array that give the items in sorted order. So for our `temp`," + "One of the ways this comes into play is trying to sort NumPy arrays using `argsort`. This function returns the indices of the array that give the items in sorted order. So for our `temp`," ] }, { @@ -620,7 +620,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "There are other numpy arg functions that return indices for operating; check out the [NumPy docs](https://numpy.org/doc/stable/reference/routines.sort.html) on sorting your arrays!" + "There are other NumPy `arg` functions that return indices for operating; check out the [NumPy docs](https://numpy.org/doc/stable/reference/routines.sort.html) on sorting your arrays!" ] }, { diff --git a/core/numpy/numpy-basics.ipynb b/core/numpy/numpy-basics.ipynb index d2ebf05eb..0d04e09c8 100644 --- a/core/numpy/numpy-basics.ipynb +++ b/core/numpy/numpy-basics.ipynb @@ -507,7 +507,23 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We can convert between degrees and radians with only NumPy." + "We can convert between degrees and radians with only NumPy, by hand" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "t / np.pi * 180" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "or with built-in function `rad2deg`," ] }, { @@ -565,7 +581,7 @@ "\n", "### Indexing\n", "\n", - "We can use integer indexing to reach into our arrays and pull out individual elements. Let's make a toy 2-d array to explore," + "We can use integer indexing to reach into our arrays and pull out individual elements. Let's make a toy 2-d array to explore. Here we create a 12-value `arange` and `reshape` it into a 3x4 array." ] }, { diff --git a/core/numpy/numpy-broadcasting.ipynb b/core/numpy/numpy-broadcasting.ipynb index b8bd5124d..ea3cafc53 100644 --- a/core/numpy/numpy-broadcasting.ipynb +++ b/core/numpy/numpy-broadcasting.ipynb @@ -14,9 +14,10 @@ "metadata": {}, "source": [ "## Overview\n", - "1. Working with multiple dimensions\n", - "1. Subsetting of irregular arrays with booleans\n", - "1. Sorting, or indexing with indices" + "Before we begin, broadcasting is a valuable part of the power that NumPy provides. However, there's no looking past the fact that broadcasting can be conceptually difficult to digest. This information can be helpful and very powerful, but we also suggest moving on to take a look at some of the label-based corners of the Python ecosystem, namely [pandas](../pandas) and [xarray](../xarray) for the ways that they make some of these concepts simpler or easier to use for real-world data.\n", + "\n", + "1. An introduction to broadcasting\n", + "1. Avoiding loops with vectorization" ] }, { @@ -281,7 +282,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This also works 2D and 1D, etc.:" + "This also works for higher dimensional broadcasting," ] }, { @@ -383,14 +384,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Broadcasting is often useful when you want to do calculations with coordinate values, which are often given as 1D arrays corresponding to positions along a particular array dimension. For example, taking range and azimiuth values for radar data (1D separable polar coordinates) and converting to x,y pairs relative to the radar location." + "Broadcasting is often useful when you want to do calculations with coordinate values, which are often given as 1-D arrays corresponding to positions along a particular array dimension. For example, taking range and azimuth values for radar data (1-D separable polar coordinates) and converting to x,y pairs relative to the radar location." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Given the 3D temperature field and 1-D pressure coordinates below, let's calculate $T * exp(P / 1000)$. We will need to use broadcasting to make the arrays compatible!" + "Given the 3-D temperature field and 1-D pressure coordinates below, let's calculate $T * exp(P / 1000)$. We will need to use broadcasting to make the arrays compatible!" ] }, { @@ -442,7 +443,11 @@ "source": [ "### Look ahead/behind\n", "\n", - "One common pattern for vectorizing is in converting loops that work over the current point as well as the previous and/or next point. This comes up when doing finite-difference calculations (e.g. approximating derivatives)" + "One common pattern for vectorizing is in converting loops that work over the current point as well as the previous and/or next point. This comes up when doing finite-difference calculations, e.g. approximating derivatives,\n", + "\n", + "\\begin{equation*}\n", + "f'(x) = f_{i+1} - f_{i}\n", + "\\end{equation*}" ] }, { @@ -478,16 +483,15 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "It would be nice to express this calculation as a loop, if possible. To see how to go about this, let's condsider the values that are involved in calculating `d[i]`, `a[i+1]` and `a[i]`. The values over the loop iterations are:\n", + "It would be nice to express this calculation without a loop, if possible. To see how to go about this, let's consider the values that are involved in calculating `d[i]`, `a[i+1]` and `a[i]`. The values over the loop iterations are:\n", "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
ia[i+1]a[i]
040
184
2128
31612
42016
\n", + "| i | a[i+1] | a[i] |\n", + "| --- | ---- | ---- |\n", + "| 0 | 4 | 0 |\n", + "| 1 | 8 | 4 |\n", + "| 2 | 12 | 8 |\n", + "| 3 | 16 | 12 |\n", + "| 4 | 20 | 16 |\n", "\n", "We can express the series of values for `a[i+1]` then as:" ] @@ -547,8 +551,11 @@ "#### 2nd Derivative\n", " \n", "A finite difference estimate of the 2nd derivative is given by:\n", - "$$f''(x) = 2\n", - "f_i - f_{i+1} - f_{i-1}$$\n", + "\n", + "\\begin{equation*}\n", + "f''(x) = 2\n", + "f_i - f_{i+1} - f_{i-1}\n", + "\\end{equation*}\n", "\n", "(we're ignoring $\\Delta x$ here)\n", "\n", @@ -632,7 +639,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Another option to solve this is not using slicing but by using a powerful numpy tool: `as_strided`. This tool can result in some odd behavior, so take care when using--the tradeoff is that this can be used to do some powerful operations. What we're doing here is altering how NumPy is interpreting the values in the memory that underpins the array. So for this array:" + "Another option to solve this is not using slicing but by using a powerful numpy tool: `as_strided`. This tool can result in some odd behavior, so take care when using--the trade-off is that this can be used to do some powerful operations. What we're doing here is altering how NumPy is interpreting the values in the memory that underpins the array. So for this array:" ] }, { @@ -648,7 +655,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "we can create a view of the array with a new, bigger shape, with rows made up of overlapping values. We do this by specifying a new shape of 8x3, one row for each of the length 3 blocks we can fit in the original 1D array of data. We then use the `strides` argument to control how numpy walks between items in each dimension. The last item in the strides tuple is just as normal--it says that the number of bytes to walk between items is just the size of an item. (Increasing this would skip items.) The first item says that when we go to a new, in this case row, only advance the size of a single item. This is what gives us overlapping rows." + "we can create a view of the array with a new, bigger shape, with rows made up of overlapping values. We do this by specifying a new shape of 8x3, one row for each of the length 3 blocks we can fit in the original 1-D array of data. We then use the `strides` argument to control how numpy walks between items in each dimension. The last item in the strides tuple is just as normal--it says that the number of bytes to walk between items is just the size of an item. (Increasing this would skip items.) The first item says that when we go to a new, in this case row, only advance the size of a single item. This is what gives us overlapping rows." ] }, { @@ -705,7 +712,7 @@ "source": [ "### Finding the difference between min and max\n", "\n", - "Another operation that crops up when slicing and dicing data is trying to identify a set of indexes, along a particular axis, within a larger multidimensional array. For instance, say we have a 3D array of temperatures, and want to identify the location of the $-10^oC$ isotherm within each column:" + "Another operation that crops up when slicing and dicing data is trying to identify a set of indexes, along a particular axis, within a larger multidimensional array. For instance, say we have a 3-D array of temperatures, and want to identify the location of the $-10^oC$ isotherm within each column:" ] }, { @@ -722,7 +729,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "NumPy has the function `argmin()` which returns the index of the minium value. We can use this to find the minimum absolute difference between the value and -10:" + "NumPy has the function `argmin()` which returns the index of the minimum value. We can use this to find the minimum absolute difference between the value and -10:" ] }, { @@ -781,7 +788,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Unfortunately, this replaced the pressure dimension (size 25) with the shape of our index array (30 x 40), giving us a 30 x 40 x 30 x 40 array (imagine what would have happened with real data!). One solution here would be to loop:\n" + "Unfortunately, this replaced the pressure dimension (size 25) with the shape of our index array (30 x 40), giving us a 30 x 40 x 30 x 40 array (imagine what would have happened with real data!). One solution here would be to loop:" ] }, { @@ -800,7 +807,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Of course, what we really want to do is avoid the explicit loop. Let's temporarily simplify the problem to a single dimension. If we have a 1D array, we can pass a 1D array of indices (a full) range, and get back the same as the original data array:" + "Of course, what we really want to do is avoid the explicit loop. Let's temporarily simplify the problem to a single dimension. If we have a 1-D array, we can pass a 1-D array of indices (a full) range, and get back the same as the original data array:" ] }, { @@ -832,7 +839,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now vectorized solution" + "Now vectorized solution:" ] }, { @@ -850,7 +857,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now let's say we want to find the relative humidity at the -10C isotherm" + "Let's say we want to find the relative humidity at the $-10^oC$ isotherm" ] }, { @@ -877,7 +884,7 @@ "We've previewed some advanced NumPy capabilities with a focus on _vectorization_, or using clever broadcasting and windows of our data to enhance the speed and readability of our calculations. Doing so can reduce explicit construction of loops in your code and keep calculations running quickly!\n", "\n", "### What's next\n", - "This is an advanced NumPy topic, and important to designing your own calculations in a way for them to be as scalable and quick as possible. Please check out some of the following links to explore this topic further." + "This is an advanced NumPy topic, and important to designing your own calculations in a way for them to be as scalable and quick as possible. Please check out some of the following links to explore this topic further. We also suggest diving into label-based indexing and subsetting with [pandas](../pandas) and [xarray](../xarray), where some of this broadcasting can be simplified or have added context." ] }, { From 8fe181ad38e9b2fef65ef8e8d897d68f9a45736f Mon Sep 17 00:00:00 2001 From: Drew Camron Date: Tue, 15 Jun 2021 16:24:33 -0600 Subject: [PATCH 14/15] Incorporate feedback --- core/numpy/intermediate-numpy.ipynb | 9 ++-- core/numpy/numpy-basics.ipynb | 74 ++++++++++++++++++++++++++--- core/numpy/numpy-broadcasting.ipynb | 21 +++++++- 3 files changed, 92 insertions(+), 12 deletions(-) diff --git a/core/numpy/intermediate-numpy.ipynb b/core/numpy/intermediate-numpy.ipynb index c550480be..eabfcd9ed 100644 --- a/core/numpy/intermediate-numpy.ipynb +++ b/core/numpy/intermediate-numpy.ipynb @@ -58,7 +58,7 @@ "source": [ "## Using axes to slice arrays\n", "\n", - "The solution to the last exercise in the Numpy Basics notebook introduces an important concept when working with NumPy: the axis. This indicates the particular dimension along which a function should operate (provided the function does something taking multiple values and converts to a single value). \n", + "Here we introduce an important concept when working with NumPy: the axis. This indicates the particular dimension along which a function should operate (provided the function does something taking multiple values and converts to a single value). \n", "\n", "Let's look at a concrete example with `sum`:" ] @@ -234,7 +234,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Finally, we can calculate the dot product of these two multidimensional fields of wind and temperature gradient components by hand as an element-wise multiplication, `*`, and then a `sum` of our separate components at each point," + "Finally, we can calculate the dot product of these two multidimensional fields of wind and temperature gradient components by hand as an element-wise multiplication, `*`, and then a `sum` of our separate components at each point (i.e., along the last `axis`)," ] }, { @@ -252,6 +252,8 @@ "metadata": {}, "source": [ "## Indexing arrays with boolean values\n", + "\n", + "### Array comparisons\n", "NumPy can easily create arrays of boolean values and use those to select certain values to extract from an array" ] }, @@ -318,7 +320,7 @@ "metadata": {}, "source": [ "
\n", - "

Info

\n", + "

Info

\n", " This only returns the values from our original array meeting the indexing conditions, nothing more! Note the size,\n", "
" ] @@ -407,6 +409,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "### Replacing values\n", "To extend this, we can use this conditional indexing to _assign_ new values to certain positions within our array, somewhat like a masking operation." ] }, diff --git a/core/numpy/numpy-basics.ipynb b/core/numpy/numpy-basics.ipynb index 0d04e09c8..1f1ce298c 100644 --- a/core/numpy/numpy-basics.ipynb +++ b/core/numpy/numpy-basics.ipynb @@ -374,7 +374,7 @@ "metadata": {}, "source": [ "
\n", - "

Warning

\n", + "

Warning

\n", " These arrays must be the same shape!\n", "
" ] @@ -408,7 +408,7 @@ "source": [ "### Constants\n", "\n", - "NumPy proves us access to some useful constants as well - remember you should never be typing these in manually! Other libraries such as SciPy and MetPy have their own set of constants that are more domain specific." + "NumPy provides us access to some useful constants as well - remember you should never be typing these in manually! Other libraries such as SciPy and MetPy have their own set of constants that are more domain specific." ] }, { @@ -474,6 +474,13 @@ "sin_t" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and clean it up a bit by `round`ing to three decimal places." + ] + }, { "cell_type": "code", "execution_count": null, @@ -498,7 +505,7 @@ "metadata": {}, "source": [ "
\n", - "

Info

\n", + "

Info

\n", " Check out NumPy's list of mathematical functions here!\n", "
" ] @@ -783,7 +790,7 @@ "metadata": {}, "source": [ "
\n", - "

Warning

\n", + "

Warning

\n", " Slice notation is exclusive of the final index.\n", "
" ] @@ -792,7 +799,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This means that slices will include ever value **up to** your `stop` index and not this index itself, like a half-open interval `[start, end)`. For example," + "This means that slices will include every value **up to** your `stop` index and not this index itself, like a half-open interval `[start, end)`. For example," ] }, { @@ -849,6 +856,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "### Multidimensional slicing\n", "This entire syntax can be extended to each dimension of multidimensional arrays." ] }, @@ -861,6 +869,13 @@ "a" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First let's pull out rows `0` through `2`, and then every `:` column for each of those" + ] + }, { "cell_type": "code", "execution_count": null, @@ -870,6 +885,13 @@ "a[0:2, :]" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Similarly, let's get all rows for just column `2`," + ] + }, { "cell_type": "code", "execution_count": null, @@ -879,6 +901,13 @@ "a[:, 2]" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "or just take a look at the full row `:`, for every second column, `::2`," + ] + }, { "cell_type": "code", "execution_count": null, @@ -892,7 +921,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "For any shape of array, you can use `...` to capture full slices of every un-specific dimension." + "For any shape of array, you can use `...` to capture full slices of every non-specified dimension. Consider the 3-D array," ] }, { @@ -914,6 +943,29 @@ "c[0, ...]" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and so this is equivalent to" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "c[0, :, :]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "for extracting every dimension across our first row. We can also flip this around," + ] + }, { "cell_type": "code", "execution_count": null, @@ -923,6 +975,13 @@ "c[..., -1]" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "to investigate every preceding dimension along our the last entry of our last axis, the same as `c[:, :, -1]`." + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -968,7 +1027,8 @@ "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.10" - } + }, + "toc-autonumbering": false }, "nbformat": 4, "nbformat_minor": 4 diff --git a/core/numpy/numpy-broadcasting.ipynb b/core/numpy/numpy-broadcasting.ipynb index ea3cafc53..3f60643ea 100644 --- a/core/numpy/numpy-broadcasting.ipynb +++ b/core/numpy/numpy-broadcasting.ipynb @@ -64,6 +64,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "### What is broadcasting?\n", "Broadcasting is a useful NumPy tool that allows us to perform operations between arrays with different shapes, provided that they are compatible with each other in certain ways. To start, we can create an array below and add 5 to it:" ] }, @@ -204,6 +205,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "### Giving NumPy room for broadcasting\n", "We can also do this using broadcasting, which is where NumPy implicitly repeats the array without using additional memory. With broadcasting, NumPy takes care of repeating for you, provided dimensions are \"compatible\". This works as:\n", "1. Check the number of dimensions of the arrays. If they are different, *prepend* size one dimensions\n", "2. Check if each of the dimensions are compatible: either the same size, or one of them is 1." @@ -282,7 +284,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This also works for higher dimensional broadcasting," + "### Extending to higher dimensions\n", + "This also works for higher dimensions. `x`, `y`, and `z` are here different dimensions, and we can broadcast to perform $x^2 + y^2 + z^2$," ] }, { @@ -296,6 +299,13 @@ "z = np.array([6, 7, 8, 9])" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, let's extend `x` (and square it) by one dimension, onto which we can broadcast the vector `y ** 2`," + ] + }, { "cell_type": "code", "execution_count": null, @@ -314,6 +324,13 @@ "d_2d.shape" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and then further extend this new 2-D array by one more dimension before using broadcasting to add `z ** 2` across all other dimensions." + ] + }, { "cell_type": "code", "execution_count": null, @@ -594,7 +611,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let's start by writing a loop to take a 3-point running mean of the data. We'll do this by iterating over all the point in the array and average the 3 points centered on that point. We'll simplify the problem by avoiding dealing with the cases at the edges of the array." + "Let's start by writing a loop to take a 3-point running mean of the data. We'll do this by iterating over all points in the array and average the 3 points centered on that point. We'll simplify the problem by avoiding dealing with the cases at the edges of the array." ] }, { From 757110423aa8b18dddaf516eac7b8af821db9998 Mon Sep 17 00:00:00 2001 From: Brian Rose Date: Tue, 15 Jun 2021 23:01:43 -0400 Subject: [PATCH 15/15] Remove extraneous data file --- core/pandas/nino_analyzed_output.csv | 473 --------------------------- 1 file changed, 473 deletions(-) delete mode 100644 core/pandas/nino_analyzed_output.csv diff --git a/core/pandas/nino_analyzed_output.csv b/core/pandas/nino_analyzed_output.csv deleted file mode 100644 index 1336c9ae0..000000000 --- a/core/pandas/nino_analyzed_output.csv +++ /dev/null @@ -1,473 +0,0 @@ -datetime,Nino12,Nino12anom,Nino3,Nino3anom,Nino4,Nino4anom,Nino34,Nino34anom,month,Nino34_degK -1982-01-01,24.29,-0.17,25.87,0.24,28.3,0.0,26.72,0.15,1,299.87 -1982-02-01,25.49,-0.58,26.38,0.01,28.21,0.11,26.7,-0.02,2,299.84999999999997 -1982-03-01,25.21,-1.31,26.98,-0.16,28.41,0.22,27.2,-0.02,3,300.34999999999997 -1982-04-01,24.5,-0.97,27.68,0.18,28.92,0.42,28.02,0.24,4,301.16999999999996 -1982-05-01,23.97,-0.23,27.79,0.71,29.49,0.7,28.54,0.69,5,301.69 -1982-06-01,22.89,0.07,27.46,1.03,29.76,0.92,28.75,1.1,6,301.9 -1982-07-01,22.47,0.87,26.44,0.82,29.38,0.58,28.1,0.88,7,301.25 -1982-08-01,21.75,1.1,26.15,1.16,29.04,0.36,27.93,1.11,8,301.08 -1982-09-01,21.8,1.44,26.52,1.67,29.16,0.47,28.11,1.39,9,301.26 -1982-10-01,22.94,2.12,27.11,2.19,29.38,0.72,28.64,1.95,10,301.78999999999996 -1982-11-01,24.59,3.0,27.62,2.64,29.23,0.6,28.81,2.16,11,301.96 -1982-12-01,26.13,3.34,28.39,3.25,29.15,0.66,29.21,2.64,12,302.35999999999996 -1983-01-01,27.42,2.96,28.92,3.29,29.0,0.7,29.36,2.79,1,302.51 -1983-02-01,28.09,2.02,28.92,2.55,28.79,0.69,29.13,2.41,2,302.28 -1983-03-01,28.68,2.16,29.1,1.96,28.76,0.57,29.03,1.81,3,302.17999999999995 -1983-04-01,28.56,3.09,29.12,1.62,28.85,0.35,28.91,1.13,4,302.06 -1983-05-01,28.19,3.99,28.97,1.89,29.08,0.29,28.89,1.04,5,302.03999999999996 -1983-06-01,27.44,4.62,28.15,1.72,28.88,0.04,28.24,0.59,6,301.39 -1983-07-01,25.95,4.35,26.62,1.0,28.65,-0.15,27.07,-0.15,7,300.21999999999997 -1983-08-01,23.78,3.13,25.87,0.88,28.38,-0.3,26.53,-0.29,8,299.67999999999995 -1983-09-01,22.24,1.88,25.24,0.39,28.23,-0.46,26.44,-0.28,9,299.59 -1983-10-01,21.86,1.04,24.61,-0.31,27.75,-0.91,25.87,-0.82,10,299.02 -1983-11-01,21.9,0.31,24.17,-0.81,27.76,-0.87,25.58,-1.07,11,298.72999999999996 -1983-12-01,23.01,0.22,24.44,-0.7,27.82,-0.67,25.59,-0.98,12,298.73999999999995 -1984-01-01,24.18,-0.28,24.82,-0.81,27.64,-0.66,25.64,-0.93,1,298.78999999999996 -1984-02-01,25.18,-0.89,26.22,-0.15,27.25,-0.85,26.39,-0.33,2,299.53999999999996 -1984-03-01,26.0,-0.52,27.12,-0.02,27.21,-0.98,26.86,-0.36,3,300.01 -1984-04-01,25.16,-0.31,27.34,-0.16,27.7,-0.8,27.39,-0.39,4,300.53999999999996 -1984-05-01,23.23,-0.97,26.46,-0.62,27.95,-0.84,27.39,-0.46,5,300.53999999999996 -1984-06-01,21.96,-0.86,25.38,-1.05,28.13,-0.71,26.86,-0.79,6,300.01 -1984-07-01,21.24,-0.36,24.96,-0.66,28.35,-0.45,26.74,-0.48,7,299.89 -1984-08-01,20.17,-0.48,24.5,-0.49,28.17,-0.51,26.34,-0.48,8,299.48999999999995 -1984-09-01,20.37,0.01,24.35,-0.5,28.61,-0.08,26.43,-0.29,9,299.58 -1984-10-01,20.52,-0.3,23.95,-0.97,28.28,-0.38,25.93,-0.76,10,299.08 -1984-11-01,21.5,-0.09,24.03,-0.95,27.99,-0.64,25.41,-1.24,11,298.56 -1984-12-01,22.58,-0.21,23.7,-1.44,27.44,-1.05,25.0,-1.57,12,298.15 -1985-01-01,23.59,-0.87,24.51,-1.12,27.71,-0.59,25.43,-1.14,1,298.58 -1985-02-01,24.87,-1.2,25.19,-1.18,27.55,-0.55,25.67,-1.05,2,298.82 -1985-03-01,25.74,-0.78,26.11,-1.03,27.38,-0.81,26.23,-0.99,3,299.38 -1985-04-01,24.25,-1.22,26.52,-0.98,27.72,-0.78,26.8,-0.98,4,299.95 -1985-05-01,22.29,-1.91,26.12,-0.96,28.06,-0.73,27.11,-0.74,5,300.26 -1985-06-01,21.75,-1.07,25.6,-0.83,28.08,-0.76,26.86,-0.79,6,300.01 -1985-07-01,20.44,-1.16,24.74,-0.88,28.28,-0.52,26.69,-0.53,7,299.84 -1985-08-01,19.29,-1.36,24.4,-0.59,28.32,-0.36,26.5,-0.32,8,299.65 -1985-09-01,19.44,-0.92,24.15,-0.7,28.33,-0.36,26.25,-0.47,9,299.4 -1985-10-01,19.9,-0.92,24.15,-0.77,28.28,-0.38,26.19,-0.5,10,299.34 -1985-11-01,20.69,-0.9,24.28,-0.7,28.52,-0.11,26.19,-0.46,11,299.34 -1985-12-01,22.4,-0.39,24.29,-0.85,28.53,0.04,26.11,-0.46,12,299.26 -1986-01-01,24.61,0.15,24.73,-0.9,28.11,-0.19,25.79,-0.78,1,298.94 -1986-02-01,26.06,-0.01,25.81,-0.56,27.93,-0.17,25.94,-0.78,2,299.09 -1986-03-01,25.91,-0.61,26.84,-0.3,27.97,-0.22,26.65,-0.57,3,299.79999999999995 -1986-04-01,24.58,-0.89,27.17,-0.33,28.21,-0.29,27.44,-0.34,4,300.59 -1986-05-01,23.38,-0.82,26.68,-0.4,28.58,-0.21,27.5,-0.35,5,300.65 -1986-06-01,21.98,-0.84,26.3,-0.13,28.84,0.0,27.69,0.04,6,300.84 -1986-07-01,21.12,-0.48,25.7,0.08,28.9,0.1,27.37,0.15,7,300.52 -1986-08-01,20.97,0.32,25.02,0.03,29.04,0.36,27.15,0.33,8,300.29999999999995 -1986-09-01,20.44,0.08,25.25,0.4,29.18,0.49,27.33,0.61,9,300.47999999999996 -1986-10-01,21.07,0.25,25.62,0.7,29.38,0.72,27.57,0.88,10,300.71999999999997 -1986-11-01,22.03,0.44,25.92,0.94,29.4,0.77,27.73,1.08,11,300.88 -1986-12-01,23.0,0.21,25.86,0.72,29.19,0.7,27.7,1.13,12,300.84999999999997 -1987-01-01,25.3,0.84,26.69,1.06,29.02,0.72,27.91,1.34,1,301.06 -1987-02-01,27.14,1.07,27.42,1.05,28.93,0.83,28.02,1.3,2,301.16999999999996 -1987-03-01,28.01,1.49,28.2,1.06,29.04,0.85,28.47,1.25,3,301.62 -1987-04-01,27.17,1.7,28.49,0.99,29.21,0.71,28.8,1.02,4,301.95 -1987-05-01,25.58,1.38,28.22,1.14,29.25,0.46,28.75,0.9,5,301.9 -1987-06-01,24.06,1.24,27.71,1.28,29.53,0.69,29.03,1.38,6,302.17999999999995 -1987-07-01,22.78,1.18,27.07,1.45,29.47,0.67,28.8,1.58,7,301.95 -1987-08-01,21.73,1.08,26.52,1.53,29.41,0.73,28.58,1.76,8,301.72999999999996 -1987-09-01,21.45,1.09,26.57,1.72,29.51,0.82,28.39,1.67,9,301.53999999999996 -1987-10-01,22.39,1.57,26.2,1.28,29.61,0.95,28.07,1.38,10,301.21999999999997 -1987-11-01,22.63,1.04,26.13,1.15,29.8,1.17,27.99,1.34,11,301.14 -1987-12-01,23.47,0.68,26.2,1.06,29.44,0.95,27.6,1.03,12,300.75 -1988-01-01,24.64,0.18,26.12,0.49,29.13,0.83,27.32,0.75,1,300.46999999999997 -1988-02-01,25.74,-0.33,26.55,0.18,28.69,0.59,27.22,0.5,2,300.37 -1988-03-01,25.78,-0.74,27.14,0.0,28.2,0.01,27.31,0.09,3,300.46 -1988-04-01,24.54,-0.93,26.73,-0.77,28.15,-0.35,27.32,-0.46,4,300.46999999999997 -1988-05-01,23.6,-0.6,25.22,-1.86,28.36,-0.43,26.48,-1.37,5,299.63 -1988-06-01,21.27,-1.55,24.46,-1.97,28.13,-0.71,26.11,-1.54,6,299.26 -1988-07-01,20.26,-1.34,23.71,-1.91,27.88,-0.92,25.57,-1.65,7,298.71999999999997 -1988-08-01,19.12,-1.53,23.37,-1.62,27.68,-1.0,25.24,-1.58,8,298.39 -1988-09-01,19.19,-1.17,23.61,-1.24,27.63,-1.06,25.43,-1.29,9,298.58 -1988-10-01,19.5,-1.32,23.17,-1.75,27.06,-1.6,24.62,-2.07,10,297.77 -1988-11-01,20.55,-1.04,23.03,-1.95,26.76,-1.87,24.27,-2.38,11,297.41999999999996 -1988-12-01,21.8,-0.99,23.07,-2.07,26.75,-1.74,24.33,-2.24,12,297.47999999999996 -1989-01-01,24.09,-0.37,24.15,-1.48,26.54,-1.76,24.53,-2.04,1,297.67999999999995 -1989-02-01,26.26,0.19,25.61,-0.76,26.55,-1.55,25.33,-1.39,2,298.47999999999996 -1989-03-01,26.66,0.14,26.02,-1.12,27.0,-1.19,25.9,-1.32,3,299.04999999999995 -1989-04-01,25.63,0.16,26.67,-0.83,27.54,-0.96,26.69,-1.09,4,299.84 -1989-05-01,23.18,-1.02,26.37,-0.71,28.14,-0.65,27.09,-0.76,5,300.23999999999995 -1989-06-01,22.0,-0.82,26.08,-0.35,27.94,-0.9,26.98,-0.67,6,300.13 -1989-07-01,21.12,-0.48,25.28,-0.34,28.2,-0.6,26.74,-0.48,7,299.89 -1989-08-01,20.32,-0.33,24.56,-0.43,28.14,-0.54,26.33,-0.49,8,299.47999999999996 -1989-09-01,19.87,-0.49,24.45,-0.4,28.25,-0.44,26.25,-0.47,9,299.4 -1989-10-01,20.33,-0.49,24.49,-0.43,28.39,-0.27,26.26,-0.43,10,299.40999999999997 -1989-11-01,21.31,-0.28,24.56,-0.42,28.23,-0.4,26.24,-0.41,11,299.39 -1989-12-01,22.19,-0.6,24.71,-0.43,28.52,0.03,26.38,-0.19,12,299.53 -1990-01-01,24.02,-0.44,25.34,-0.29,28.56,0.26,26.55,-0.02,1,299.7 -1990-02-01,25.88,-0.19,26.37,0.0,28.62,0.52,26.95,0.23,2,300.09999999999997 -1990-03-01,26.16,-0.36,27.03,-0.11,28.78,0.59,27.46,0.24,3,300.60999999999996 -1990-04-01,25.22,-0.25,27.67,0.17,28.93,0.43,28.02,0.24,4,301.16999999999996 -1990-05-01,24.05,-0.15,27.35,0.27,28.96,0.17,28.06,0.21,5,301.21 -1990-06-01,22.68,-0.14,26.45,0.02,28.94,0.1,27.58,-0.07,6,300.72999999999996 -1990-07-01,21.0,-0.6,25.45,-0.17,28.98,0.18,27.25,0.03,7,300.4 -1990-08-01,20.25,-0.4,25.06,0.07,29.17,0.49,27.05,0.23,8,300.2 -1990-09-01,20.13,-0.23,24.85,0.0,29.04,0.35,26.75,0.03,9,299.9 -1990-10-01,20.28,-0.54,24.9,-0.02,29.23,0.57,26.98,0.29,10,300.13 -1990-11-01,20.84,-0.75,24.82,-0.16,29.06,0.43,26.72,0.07,11,299.87 -1990-12-01,22.45,-0.34,25.08,-0.06,29.14,0.65,26.91,0.34,12,300.06 -1991-01-01,23.86,-0.6,25.65,0.02,29.0,0.7,27.01,0.44,1,300.15999999999997 -1991-02-01,25.97,-0.1,26.27,-0.1,28.73,0.63,26.93,0.21,2,300.08 -1991-03-01,26.51,-0.01,26.99,-0.15,28.64,0.45,27.25,0.03,3,300.4 -1991-04-01,24.99,-0.48,27.32,-0.18,29.13,0.63,27.98,0.2,4,301.13 -1991-05-01,24.37,0.17,27.58,0.5,29.42,0.63,28.35,0.5,5,301.5 -1991-06-01,23.05,0.23,27.34,0.91,29.35,0.51,28.36,0.71,6,301.51 -1991-07-01,22.05,0.45,26.57,0.95,29.26,0.46,27.92,0.7,7,301.07 -1991-08-01,21.08,0.43,25.47,0.48,29.25,0.57,27.44,0.62,8,300.59 -1991-09-01,20.75,0.39,25.05,0.2,29.19,0.5,27.07,0.35,9,300.21999999999997 -1991-10-01,21.13,0.31,25.6,0.68,29.44,0.78,27.63,0.94,10,300.78 -1991-11-01,22.18,0.59,25.98,1.0,29.45,0.82,27.86,1.21,11,301.01 -1991-12-01,23.43,0.64,26.52,1.38,29.45,0.96,28.37,1.8,12,301.52 -1992-01-01,24.83,0.37,27.0,1.37,29.06,0.76,28.41,1.84,1,301.56 -1992-02-01,26.68,0.61,27.67,1.3,29.02,0.92,28.63,1.91,2,301.78 -1992-03-01,27.76,1.24,28.33,1.19,29.08,0.89,28.83,1.61,3,301.97999999999996 -1992-04-01,27.68,2.21,28.72,1.22,29.42,0.92,29.14,1.36,4,302.28999999999996 -1992-05-01,26.31,2.11,28.43,1.35,29.46,0.67,28.99,1.14,5,302.14 -1992-06-01,23.82,1.0,26.66,0.23,29.31,0.47,28.02,0.37,6,301.16999999999996 -1992-07-01,21.95,0.35,25.53,-0.09,29.35,0.55,27.53,0.31,7,300.67999999999995 -1992-08-01,20.55,-0.1,24.7,-0.29,28.9,0.22,26.64,-0.18,8,299.78999999999996 -1992-09-01,20.06,-0.3,24.52,-0.33,28.79,0.1,26.48,-0.24,9,299.63 -1992-10-01,20.82,0.0,24.62,-0.3,28.69,0.03,26.34,-0.35,10,299.48999999999995 -1992-11-01,21.49,-0.1,24.79,-0.19,28.7,0.07,26.51,-0.14,11,299.65999999999997 -1992-12-01,22.48,-0.31,25.01,-0.13,28.76,0.27,26.73,0.16,12,299.88 -1993-01-01,24.43,-0.03,25.56,-0.07,28.6,0.3,26.69,0.12,1,299.84 -1993-02-01,26.49,0.42,26.61,0.24,28.41,0.31,26.97,0.25,2,300.12 -1993-03-01,27.17,0.65,27.54,0.4,28.6,0.41,27.66,0.44,3,300.81 -1993-04-01,26.44,0.97,28.45,0.95,28.93,0.43,28.59,0.81,4,301.73999999999995 -1993-05-01,25.15,0.95,28.16,1.08,29.13,0.34,28.82,0.97,5,301.96999999999997 -1993-06-01,23.76,0.94,27.11,0.68,29.17,0.33,28.28,0.63,6,301.42999999999995 -1993-07-01,22.06,0.46,25.77,0.15,29.2,0.4,27.55,0.33,7,300.7 -1993-08-01,21.05,0.4,24.93,-0.06,28.94,0.26,26.84,0.02,8,299.98999999999995 -1993-09-01,20.83,0.47,24.97,0.12,29.07,0.38,26.92,0.2,9,300.07 -1993-10-01,20.99,0.17,25.21,0.29,28.9,0.24,26.93,0.24,10,300.08 -1993-11-01,21.64,0.05,25.17,0.19,28.97,0.34,26.91,0.26,11,300.06 -1993-12-01,22.75,-0.04,25.32,0.18,28.9,0.41,26.76,0.19,12,299.90999999999997 -1994-01-01,24.32,-0.14,25.71,0.08,28.47,0.17,26.6,0.03,1,299.75 -1994-02-01,25.79,-0.28,26.07,-0.3,28.07,-0.03,26.59,-0.13,2,299.73999999999995 -1994-03-01,25.43,-1.09,26.89,-0.25,28.26,0.07,27.27,0.05,3,300.41999999999996 -1994-04-01,24.32,-1.15,27.06,-0.44,28.62,0.12,27.9,0.12,4,301.04999999999995 -1994-05-01,23.22,-0.98,26.97,-0.11,29.0,0.21,28.04,0.19,5,301.19 -1994-06-01,22.43,-0.39,26.5,0.07,29.18,0.34,27.99,0.34,6,301.14 -1994-07-01,21.21,-0.39,25.19,-0.43,29.4,0.6,27.35,0.13,7,300.5 -1994-08-01,19.7,-0.95,24.71,-0.28,29.46,0.78,27.35,0.53,8,300.5 -1994-09-01,20.16,-0.2,24.81,-0.04,29.23,0.54,27.0,0.28,9,300.15 -1994-10-01,21.53,0.71,25.53,0.61,29.45,0.79,27.49,0.8,10,300.64 -1994-11-01,22.41,0.82,25.87,0.89,29.63,1.0,27.87,1.22,11,301.02 -1994-12-01,23.61,0.82,26.07,0.93,29.5,1.01,27.87,1.3,12,301.02 -1995-01-01,25.33,0.87,26.34,0.71,29.2,0.9,27.55,0.98,1,300.7 -1995-02-01,26.43,0.36,26.87,0.5,29.01,0.91,27.45,0.73,2,300.59999999999997 -1995-03-01,26.12,-0.4,27.08,-0.06,28.96,0.77,27.63,0.41,3,300.78 -1995-04-01,24.47,-1.0,27.1,-0.4,28.89,0.39,27.93,0.15,4,301.08 -1995-05-01,23.1,-1.1,26.4,-0.68,29.15,0.36,27.73,-0.12,5,300.88 -1995-06-01,22.45,-0.37,26.2,-0.23,29.01,0.17,27.59,-0.06,6,300.73999999999995 -1995-07-01,21.23,-0.37,25.42,-0.2,28.78,-0.02,27.01,-0.21,7,300.15999999999997 -1995-08-01,20.01,-0.64,24.33,-0.66,28.43,-0.25,26.33,-0.49,8,299.47999999999996 -1995-09-01,20.17,-0.19,24.02,-0.83,28.25,-0.44,25.96,-0.76,9,299.10999999999996 -1995-10-01,20.15,-0.67,24.01,-0.91,28.07,-0.59,25.67,-1.02,10,298.82 -1995-11-01,21.2,-0.39,24.03,-0.95,27.97,-0.66,25.66,-0.99,11,298.81 -1995-12-01,22.02,-0.77,24.19,-0.95,28.07,-0.42,25.57,-1.0,12,298.71999999999997 -1996-01-01,23.84,-0.62,24.96,-0.67,27.92,-0.38,25.74,-0.83,1,298.89 -1996-02-01,25.71,-0.36,25.72,-0.65,27.57,-0.53,25.85,-0.87,2,299.0 -1996-03-01,26.09,-0.43,26.71,-0.43,27.71,-0.48,26.62,-0.6,3,299.77 -1996-04-01,23.85,-1.62,26.72,-0.78,28.07,-0.43,27.36,-0.42,4,300.51 -1996-05-01,22.89,-1.31,26.33,-0.75,28.43,-0.36,27.37,-0.48,5,300.52 -1996-06-01,21.56,-1.26,25.89,-0.54,28.55,-0.29,27.32,-0.33,6,300.46999999999997 -1996-07-01,20.02,-1.58,25.35,-0.27,28.5,-0.3,27.09,-0.13,7,300.23999999999995 -1996-08-01,19.53,-1.12,24.6,-0.39,28.54,-0.14,26.56,-0.26,8,299.71 -1996-09-01,19.24,-1.12,24.37,-0.48,28.43,-0.26,26.35,-0.37,9,299.5 -1996-10-01,19.95,-0.87,24.37,-0.55,28.42,-0.24,26.24,-0.45,10,299.39 -1996-11-01,20.26,-1.33,24.38,-0.6,28.33,-0.3,26.19,-0.46,11,299.34 -1996-12-01,21.61,-1.18,24.2,-0.94,28.44,-0.05,26.02,-0.55,12,299.16999999999996 -1997-01-01,23.67,-0.79,24.7,-0.93,28.41,0.11,25.96,-0.61,1,299.10999999999996 -1997-02-01,25.74,-0.33,25.75,-0.62,28.33,0.23,26.36,-0.36,2,299.51 -1997-03-01,26.95,0.43,26.98,-0.16,28.52,0.33,27.03,-0.19,3,300.17999999999995 -1997-04-01,26.64,1.17,27.59,0.09,29.32,0.82,28.03,0.25,4,301.17999999999995 -1997-05-01,26.71,2.51,28.06,0.98,29.45,0.66,28.6,0.75,5,301.75 -1997-06-01,26.27,3.45,28.14,1.71,29.4,0.56,28.94,1.29,6,302.09 -1997-07-01,25.59,3.99,28.01,2.39,29.5,0.7,28.92,1.7,7,302.07 -1997-08-01,24.8,4.15,27.84,2.85,29.26,0.58,28.84,2.02,8,301.98999999999995 -1997-09-01,24.4,4.04,27.84,2.99,29.32,0.63,28.93,2.21,9,302.08 -1997-10-01,24.58,3.76,28.17,3.25,29.32,0.66,29.23,2.54,10,302.38 -1997-11-01,25.63,4.04,28.55,3.57,29.49,0.86,29.32,2.67,11,302.46999999999997 -1997-12-01,26.92,4.13,28.76,3.62,29.32,0.83,29.26,2.69,12,302.40999999999997 -1998-01-01,28.22,3.76,28.94,3.31,29.01,0.71,29.1,2.53,1,302.25 -1998-02-01,28.98,2.91,28.93,2.56,28.87,0.77,28.86,2.14,2,302.01 -1998-03-01,29.15,2.63,29.14,2.0,28.65,0.46,28.67,1.45,3,301.82 -1998-04-01,28.61,3.14,29.09,1.59,28.53,0.03,28.56,0.78,4,301.71 -1998-05-01,27.69,3.49,28.17,1.09,28.71,-0.08,28.47,0.62,5,301.62 -1998-06-01,25.18,2.36,26.0,-0.43,28.61,-0.23,26.72,-0.93,6,299.87 -1998-07-01,23.43,1.83,25.24,-0.38,28.07,-0.73,25.94,-1.28,7,299.09 -1998-08-01,21.77,1.12,24.63,-0.36,27.77,-0.91,25.49,-1.33,8,298.64 -1998-09-01,20.87,0.51,24.19,-0.66,27.88,-0.81,25.61,-1.11,9,298.76 -1998-10-01,21.16,0.34,24.06,-0.86,27.33,-1.33,25.34,-1.35,10,298.48999999999995 -1998-11-01,21.43,-0.16,24.11,-0.87,27.23,-1.4,25.18,-1.47,11,298.33 -1998-12-01,22.56,-0.23,23.86,-1.28,27.11,-1.38,24.79,-1.78,12,297.94 -1999-01-01,23.73,-0.73,24.41,-1.22,26.59,-1.71,24.9,-1.67,1,298.04999999999995 -1999-02-01,25.64,-0.43,25.57,-0.8,26.52,-1.58,25.41,-1.31,2,298.56 -1999-03-01,26.62,0.1,26.67,-0.47,26.9,-1.29,26.25,-0.97,3,299.4 -1999-04-01,24.3,-1.17,26.66,-0.84,27.35,-1.15,26.84,-0.94,4,299.98999999999995 -1999-05-01,23.46,-0.74,26.44,-0.64,27.87,-0.92,26.97,-0.88,5,300.12 -1999-06-01,21.83,-0.99,25.59,-0.84,28.01,-0.83,26.6,-1.05,6,299.75 -1999-07-01,20.44,-1.16,24.85,-0.77,27.92,-0.88,26.35,-0.87,7,299.5 -1999-08-01,19.75,-0.9,24.02,-0.97,27.73,-0.95,25.59,-1.23,8,298.73999999999995 -1999-09-01,19.23,-1.13,23.72,-1.13,27.82,-0.87,25.71,-1.01,9,298.85999999999996 -1999-10-01,20.05,-0.77,23.75,-1.17,27.85,-0.81,25.64,-1.05,10,298.78999999999996 -1999-11-01,20.51,-1.08,23.46,-1.52,27.56,-1.07,25.12,-1.53,11,298.27 -1999-12-01,21.72,-1.07,23.54,-1.6,27.23,-1.26,24.9,-1.67,12,298.04999999999995 -2000-01-01,23.86,-0.6,23.88,-1.75,26.96,-1.34,24.65,-1.92,1,297.79999999999995 -2000-02-01,25.71,-0.36,25.31,-1.06,26.66,-1.44,25.19,-1.53,2,298.34 -2000-03-01,26.19,-0.33,26.61,-0.53,26.76,-1.43,26.08,-1.14,3,299.22999999999996 -2000-04-01,25.84,0.37,27.46,-0.04,27.37,-1.13,27.01,-0.77,4,300.15999999999997 -2000-05-01,24.1,-0.1,26.8,-0.28,27.81,-0.98,27.12,-0.73,5,300.27 -2000-06-01,22.25,-0.57,25.84,-0.59,28.11,-0.73,27.03,-0.62,6,300.17999999999995 -2000-07-01,20.59,-1.01,25.13,-0.49,28.2,-0.6,26.72,-0.5,7,299.87 -2000-08-01,20.1,-0.55,24.47,-0.52,28.32,-0.36,26.45,-0.37,8,299.59999999999997 -2000-09-01,19.94,-0.42,24.35,-0.5,28.44,-0.25,26.21,-0.51,9,299.35999999999996 -2000-10-01,20.37,-0.45,24.41,-0.51,28.17,-0.49,25.96,-0.73,10,299.10999999999996 -2000-11-01,20.6,-0.99,24.17,-0.81,28.09,-0.54,25.78,-0.87,11,298.92999999999995 -2000-12-01,22.22,-0.57,24.43,-0.71,27.6,-0.89,25.59,-0.98,12,298.73999999999995 -2001-01-01,23.88,-0.58,24.99,-0.64,27.5,-0.8,25.74,-0.83,1,298.89 -2001-02-01,25.91,-0.16,26.06,-0.31,27.27,-0.83,26.11,-0.61,2,299.26 -2001-03-01,27.44,0.92,27.23,0.09,27.62,-0.57,26.84,-0.38,3,299.98999999999995 -2001-04-01,26.69,1.22,27.52,0.02,28.19,-0.31,27.52,-0.26,4,300.66999999999996 -2001-05-01,23.77,-0.43,26.89,-0.19,28.64,-0.15,27.6,-0.25,5,300.75 -2001-06-01,21.74,-1.08,26.35,-0.08,28.83,-0.01,27.68,0.03,6,300.83 -2001-07-01,20.88,-0.72,25.43,-0.19,29.06,0.26,27.32,0.1,7,300.46999999999997 -2001-08-01,19.9,-0.75,24.72,-0.27,28.96,0.28,26.87,0.05,8,300.02 -2001-09-01,19.39,-0.97,24.27,-0.58,29.14,0.45,26.55,-0.17,9,299.7 -2001-10-01,19.52,-1.3,24.45,-0.47,29.01,0.35,26.59,-0.1,10,299.73999999999995 -2001-11-01,20.49,-1.1,24.35,-0.63,28.96,0.33,26.45,-0.2,11,299.59999999999997 -2001-12-01,21.96,-0.83,24.6,-0.54,28.6,0.11,26.17,-0.4,12,299.32 -2002-01-01,23.64,-0.82,25.09,-0.54,28.81,0.51,26.5,-0.07,1,299.65 -2002-02-01,26.06,-0.01,26.21,-0.16,28.76,0.66,26.95,0.23,2,300.09999999999997 -2002-03-01,27.53,1.01,27.22,0.08,28.68,0.49,27.32,0.1,3,300.46999999999997 -2002-04-01,26.53,1.06,27.56,0.06,29.09,0.59,27.94,0.16,4,301.09 -2002-05-01,24.8,0.6,27.24,0.16,29.45,0.66,28.15,0.3,5,301.29999999999995 -2002-06-01,22.67,-0.15,27.06,0.63,29.63,0.79,28.43,0.78,6,301.58 -2002-07-01,21.01,-0.59,26.03,0.41,29.49,0.69,27.98,0.76,7,301.13 -2002-08-01,19.94,-0.71,25.47,0.48,29.4,0.72,27.79,0.97,8,300.94 -2002-09-01,19.89,-0.47,25.54,0.69,29.44,0.75,27.83,1.11,9,300.97999999999996 -2002-10-01,21.16,0.34,25.85,0.93,29.56,0.9,28.05,1.36,10,301.2 -2002-11-01,22.25,0.66,26.37,1.39,29.83,1.2,28.27,1.62,11,301.41999999999996 -2002-12-01,23.44,0.65,26.48,1.34,29.49,1.0,28.09,1.52,12,301.23999999999995 -2003-01-01,24.38,-0.08,26.38,0.75,29.25,0.95,27.76,1.19,1,300.90999999999997 -2003-02-01,25.81,-0.26,26.7,0.33,29.03,0.93,27.49,0.77,2,300.64 -2003-03-01,25.97,-0.55,27.28,0.14,29.03,0.84,27.81,0.59,3,300.96 -2003-04-01,24.44,-1.03,27.15,-0.35,28.96,0.46,27.81,0.03,4,300.96 -2003-05-01,22.49,-1.71,26.14,-0.94,28.92,0.13,27.37,-0.48,5,300.52 -2003-06-01,21.58,-1.24,25.83,-0.6,29.09,0.25,27.48,-0.17,6,300.63 -2003-07-01,20.75,-0.85,25.75,0.13,29.11,0.31,27.43,0.21,7,300.58 -2003-08-01,20.14,-0.51,25.04,0.05,29.05,0.37,26.85,0.03,8,300.0 -2003-09-01,20.0,-0.36,24.97,0.12,29.02,0.33,26.96,0.24,9,300.10999999999996 -2003-10-01,20.99,0.17,25.33,0.41,29.22,0.56,27.19,0.5,10,300.34 -2003-11-01,21.92,0.33,25.4,0.42,29.31,0.68,27.05,0.4,11,300.2 -2003-12-01,22.99,0.2,25.56,0.42,29.02,0.53,26.89,0.32,12,300.03999999999996 -2004-01-01,24.6,0.14,25.92,0.29,28.83,0.53,26.74,0.17,1,299.89 -2004-02-01,25.81,-0.26,26.46,0.09,28.59,0.49,26.86,0.14,2,300.01 -2004-03-01,25.94,-0.58,27.16,0.02,28.43,0.24,27.1,-0.12,3,300.25 -2004-04-01,25.32,-0.15,27.37,-0.13,28.75,0.25,27.84,0.06,4,300.98999999999995 -2004-05-01,23.05,-1.15,26.72,-0.36,29.16,0.37,28.06,0.21,5,301.21 -2004-06-01,21.6,-1.22,26.27,-0.16,29.17,0.33,27.76,0.11,6,300.90999999999997 -2004-07-01,20.71,-0.89,25.41,-0.21,29.39,0.59,27.69,0.47,7,300.84 -2004-08-01,19.62,-1.03,25.05,0.06,29.31,0.63,27.54,0.72,8,300.69 -2004-09-01,20.07,-0.29,25.17,0.32,29.6,0.91,27.47,0.75,9,300.62 -2004-10-01,20.92,0.1,25.32,0.4,29.55,0.89,27.38,0.69,10,300.53 -2004-11-01,21.96,0.37,25.46,0.48,29.57,0.94,27.31,0.66,11,300.46 -2004-12-01,22.94,0.15,25.77,0.63,29.4,0.91,27.31,0.74,12,300.46 -2005-01-01,24.47,0.01,25.89,0.26,29.21,0.91,27.1,0.53,1,300.25 -2005-02-01,25.49,-0.58,26.2,-0.17,28.83,0.73,26.96,0.24,2,300.10999999999996 -2005-03-01,25.6,-0.92,27.01,-0.13,28.91,0.72,27.55,0.33,3,300.7 -2005-04-01,24.9,-0.57,27.77,0.27,28.96,0.46,28.07,0.29,4,301.21999999999997 -2005-05-01,24.4,0.2,27.48,0.4,29.18,0.39,28.2,0.35,5,301.34999999999997 -2005-06-01,22.47,-0.35,26.81,0.38,29.18,0.34,28.05,0.4,6,301.2 -2005-07-01,21.18,-0.42,25.93,0.31,29.05,0.25,27.47,0.25,7,300.62 -2005-08-01,20.61,-0.04,25.19,0.2,28.86,0.18,26.88,0.06,8,300.03 -2005-09-01,19.71,-0.65,24.57,-0.28,28.84,0.15,26.63,-0.09,9,299.78 -2005-10-01,19.72,-1.1,24.69,-0.23,28.89,0.23,26.75,0.06,10,299.9 -2005-11-01,20.62,-0.97,24.28,-0.7,28.67,0.04,26.34,-0.31,11,299.48999999999995 -2005-12-01,22.29,-0.5,24.28,-0.86,28.35,-0.14,25.89,-0.68,12,299.03999999999996 -2006-01-01,24.33,-0.13,25.0,-0.63,27.68,-0.62,25.64,-0.93,1,298.78999999999996 -2006-02-01,26.46,0.39,26.08,-0.29,27.39,-0.71,26.08,-0.64,2,299.22999999999996 -2006-03-01,26.77,0.25,26.54,-0.6,27.79,-0.4,26.57,-0.65,3,299.71999999999997 -2006-04-01,24.15,-1.32,27.25,-0.25,28.38,-0.12,27.59,-0.19,4,300.73999999999995 -2006-05-01,23.86,-0.34,27.04,-0.04,28.91,0.12,27.91,0.06,5,301.06 -2006-06-01,22.77,-0.05,26.44,0.01,29.15,0.31,27.85,0.2,6,301.0 -2006-07-01,22.19,0.59,25.8,0.18,29.07,0.27,27.35,0.13,7,300.5 -2006-08-01,21.59,0.94,25.45,0.46,29.22,0.54,27.22,0.4,8,300.37 -2006-09-01,21.43,1.07,25.74,0.89,29.4,0.71,27.34,0.62,9,300.48999999999995 -2006-10-01,22.22,1.4,25.96,1.04,29.44,0.78,27.47,0.78,10,300.62 -2006-11-01,22.69,1.1,26.07,1.09,29.63,1.0,27.73,1.08,11,300.88 -2006-12-01,23.45,0.66,26.36,1.22,29.47,0.98,27.76,1.19,12,300.90999999999997 -2007-01-01,24.99,0.53,26.5,0.87,28.93,0.63,27.26,0.69,1,300.40999999999997 -2007-02-01,26.24,0.17,26.45,0.08,28.62,0.52,26.81,0.09,2,299.96 -2007-03-01,25.74,-0.78,26.79,-0.35,28.57,0.38,27.18,-0.04,3,300.33 -2007-04-01,24.3,-1.17,27.13,-0.37,28.7,0.2,27.78,0.0,4,300.92999999999995 -2007-05-01,22.73,-1.47,26.35,-0.73,28.86,0.07,27.57,-0.28,5,300.71999999999997 -2007-06-01,21.59,-1.23,25.83,-0.6,28.98,0.14,27.55,-0.1,6,300.7 -2007-07-01,20.27,-1.33,24.79,-0.83,28.81,0.01,26.79,-0.43,7,299.94 -2007-08-01,19.16,-1.49,23.86,-1.13,28.58,-0.1,26.2,-0.62,8,299.34999999999997 -2007-09-01,18.57,-1.79,23.52,-1.33,28.12,-0.57,25.77,-0.95,9,298.91999999999996 -2007-10-01,18.8,-2.02,23.36,-1.56,27.86,-0.8,25.22,-1.47,10,298.37 -2007-11-01,19.49,-2.1,23.17,-1.81,27.42,-1.21,25.06,-1.59,11,298.21 -2007-12-01,21.02,-1.77,23.59,-1.55,27.3,-1.19,24.97,-1.6,12,298.12 -2008-01-01,23.86,-0.6,24.13,-1.5,26.62,-1.68,24.71,-1.86,1,297.85999999999996 -2008-02-01,26.32,0.25,25.05,-1.32,26.43,-1.67,24.83,-1.89,2,297.97999999999996 -2008-03-01,27.3,0.78,26.56,-0.58,26.84,-1.35,26.07,-1.15,3,299.21999999999997 -2008-04-01,25.89,0.42,27.18,-0.32,27.44,-1.06,26.83,-0.95,4,299.97999999999996 -2008-05-01,24.41,0.21,27.08,0.0,27.9,-0.89,27.18,-0.67,5,300.33 -2008-06-01,23.55,0.73,26.53,0.1,28.08,-0.76,27.17,-0.48,6,300.32 -2008-07-01,22.63,1.03,26.12,0.5,28.25,-0.55,27.19,-0.03,7,300.34 -2008-08-01,21.79,1.14,25.63,0.64,28.18,-0.5,26.85,0.03,8,300.0 -2008-09-01,21.19,0.83,25.09,0.24,28.14,-0.55,26.44,-0.28,9,299.59 -2008-10-01,20.75,-0.07,24.79,-0.13,28.29,-0.37,26.33,-0.36,10,299.47999999999996 -2008-11-01,21.44,-0.15,24.75,-0.23,28.08,-0.55,26.3,-0.35,11,299.45 -2008-12-01,22.43,-0.36,24.6,-0.54,27.72,-0.77,25.74,-0.83,12,298.89 -2009-01-01,24.42,-0.1,25.03,-0.6,27.42,-0.88,25.54,-1.03,1,298.69 -2009-02-01,26.03,-0.11,25.85,-0.52,27.37,-0.73,26.04,-0.68,2,299.19 -2009-03-01,26.38,-0.26,26.44,-0.7,27.79,-0.4,26.67,-0.55,3,299.82 -2009-04-01,25.98,0.37,27.39,-0.11,28.37,-0.13,27.5,-0.27,4,300.65 -2009-05-01,24.83,0.56,27.4,0.32,28.99,0.2,28.03,0.18,5,301.17999999999995 -2009-06-01,23.73,0.85,27.12,0.69,29.2,0.36,28.11,0.47,6,301.26 -2009-07-01,22.63,1.02,26.56,0.94,29.21,0.4,27.94,0.72,7,301.09 -2009-08-01,21.64,1.0,25.94,0.95,29.21,0.53,27.53,0.71,8,300.67999999999995 -2009-09-01,20.82,0.47,25.66,0.8,29.28,0.58,27.47,0.75,9,300.62 -2009-10-01,20.96,0.17,25.73,0.81,29.65,0.99,27.63,0.94,10,300.78 -2009-11-01,22.11,0.51,26.23,1.26,29.88,1.25,28.19,1.54,11,301.34 -2009-12-01,23.16,0.35,26.67,1.53,29.67,1.18,28.3,1.72,12,301.45 -2010-01-01,24.82,0.3,26.63,1.0,29.51,1.21,28.07,1.5,1,301.21999999999997 -2010-02-01,26.08,-0.06,27.12,0.75,29.1,1.0,27.94,1.22,2,301.09 -2010-03-01,26.24,-0.4,27.73,0.6,29.21,1.02,28.29,1.08,3,301.44 -2010-04-01,26.05,0.45,28.05,0.55,29.25,0.74,28.36,0.59,4,301.51 -2010-05-01,24.28,0.0,26.97,-0.11,29.03,0.24,27.68,-0.17,5,300.83 -2010-06-01,22.6,-0.27,25.75,-0.68,28.64,-0.21,27.0,-0.65,6,300.15 -2010-07-01,20.08,-1.54,24.53,-1.09,28.09,-0.71,26.09,-1.13,7,299.23999999999995 -2010-08-01,19.27,-1.37,23.87,-1.12,27.47,-1.2,25.5,-1.32,8,298.65 -2010-09-01,18.9,-1.44,23.59,-1.26,27.13,-1.56,25.07,-1.65,9,298.21999999999997 -2010-10-01,19.06,-1.73,23.25,-1.66,27.06,-1.6,25.01,-1.68,10,298.15999999999997 -2010-11-01,20.03,-1.56,23.4,-1.58,27.07,-1.57,25.07,-1.58,11,298.21999999999997 -2010-12-01,21.48,-1.34,23.5,-1.64,26.89,-1.6,24.95,-1.62,12,298.09999999999997 -2011-01-01,24.08,-0.44,24.31,-1.32,26.72,-1.58,24.93,-1.64,1,298.08 -2011-02-01,26.22,0.08,25.55,-0.82,26.95,-1.15,25.46,-1.27,2,298.60999999999996 -2011-03-01,26.21,-0.43,26.39,-0.75,27.42,-0.77,26.23,-0.98,3,299.38 -2011-04-01,25.76,0.16,27.18,-0.32,27.86,-0.64,27.02,-0.76,4,300.16999999999996 -2011-05-01,24.89,0.62,26.94,-0.14,28.28,-0.51,27.42,-0.43,5,300.57 -2011-06-01,23.72,0.85,26.54,0.1,28.47,-0.37,27.46,-0.18,6,300.60999999999996 -2011-07-01,22.07,0.45,25.61,-0.01,28.47,-0.33,26.96,-0.26,7,300.10999999999996 -2011-08-01,20.64,0.0,24.58,-0.42,28.32,-0.36,26.19,-0.64,8,299.34 -2011-09-01,19.75,-0.59,24.22,-0.63,28.05,-0.64,25.98,-0.74,9,299.13 -2011-10-01,20.19,-0.6,23.97,-0.95,27.94,-0.72,25.72,-0.97,10,298.87 -2011-11-01,20.79,-0.8,23.89,-1.09,27.87,-0.77,25.6,-1.05,11,298.75 -2011-12-01,21.85,-0.96,24.2,-0.94,27.39,-1.1,25.53,-1.04,12,298.67999999999995 -2012-01-01,23.88,-0.64,24.9,-0.73,27.09,-1.21,25.49,-1.08,1,298.64 -2012-02-01,26.3,0.16,26.19,-0.18,27.2,-0.9,26.03,-0.69,2,299.17999999999995 -2012-03-01,26.91,0.27,26.92,-0.21,27.53,-0.66,26.63,-0.58,3,299.78 -2012-04-01,26.9,1.3,27.58,0.08,28.16,-0.34,27.38,-0.39,4,300.53 -2012-05-01,25.48,1.2,27.23,0.15,28.53,-0.26,27.8,-0.05,5,300.95 -2012-06-01,24.47,1.59,27.09,0.66,28.73,-0.11,27.95,0.31,6,301.09999999999997 -2012-07-01,22.61,0.99,26.54,0.92,28.86,0.06,27.75,0.53,7,300.9 -2012-08-01,20.99,0.35,25.72,0.73,29.1,0.42,27.55,0.73,8,300.7 -2012-09-01,20.83,0.49,25.28,0.43,29.12,0.43,27.24,0.51,9,300.39 -2012-10-01,20.68,-0.11,24.93,0.01,29.16,0.5,26.98,0.29,10,300.13 -2012-11-01,21.21,-0.38,25.11,0.14,29.17,0.54,27.01,0.36,11,300.15999999999997 -2012-12-01,22.13,-0.68,24.91,-0.23,28.71,0.23,26.46,-0.11,12,299.60999999999996 -2013-01-01,24.0,-0.52,25.06,-0.57,28.28,-0.02,26.16,-0.41,1,299.31 -2013-02-01,25.74,-0.41,25.9,-0.46,28.06,-0.04,26.32,-0.4,2,299.46999999999997 -2013-03-01,26.71,0.07,27.21,0.07,27.95,-0.24,27.0,-0.22,3,300.15 -2013-04-01,24.74,-0.86,27.35,-0.15,28.47,-0.03,27.68,-0.1,4,300.83 -2013-05-01,22.89,-1.38,26.39,-0.69,28.71,-0.08,27.57,-0.27,5,300.71999999999997 -2013-06-01,21.48,-1.4,25.8,-0.64,28.76,-0.08,27.43,-0.21,6,300.58 -2013-07-01,20.29,-1.33,24.97,-0.66,28.76,-0.04,26.91,-0.31,7,300.06 -2013-08-01,19.66,-0.98,24.44,-0.55,28.71,0.03,26.54,-0.28,8,299.69 -2013-09-01,19.78,-0.57,24.72,-0.13,28.7,0.01,26.65,-0.07,9,299.79999999999995 -2013-10-01,20.16,-0.63,24.7,-0.21,28.7,0.04,26.36,-0.33,10,299.51 -2013-11-01,21.06,-0.54,24.81,-0.17,28.91,0.27,26.65,0.01,11,299.79999999999995 -2013-12-01,22.61,-0.2,25.1,-0.04,28.64,0.15,26.53,-0.04,12,299.67999999999995 -2014-01-01,24.79,0.27,25.26,-0.37,28.14,-0.17,26.06,-0.51,1,299.21 -2014-02-01,25.4,-0.75,25.56,-0.81,28.37,0.27,26.18,-0.55,2,299.33 -2014-03-01,25.86,-0.78,26.9,-0.24,28.71,0.52,26.99,-0.22,3,300.14 -2014-04-01,25.23,-0.37,27.73,0.23,29.13,0.63,28.01,0.24,4,301.15999999999997 -2014-05-01,25.57,1.3,27.69,0.61,29.56,0.77,28.31,0.46,5,301.46 -2014-06-01,24.51,1.64,27.32,0.89,29.43,0.59,28.11,0.46,6,301.26 -2014-07-01,22.98,1.36,26.27,0.65,29.09,0.29,27.4,0.18,7,300.54999999999995 -2014-08-01,21.91,1.27,25.51,0.52,29.14,0.46,27.02,0.2,8,300.16999999999996 -2014-09-01,21.3,0.96,25.31,0.45,29.34,0.65,27.17,0.45,9,300.32 -2014-10-01,21.54,0.75,25.58,0.66,29.31,0.64,27.17,0.49,10,300.32 -2014-11-01,22.33,0.74,25.88,0.91,29.52,0.88,27.5,0.85,11,300.65 -2014-12-01,22.9,0.08,25.94,0.8,29.4,0.91,27.35,0.78,12,300.5 -2015-01-01,24.13,-0.39,25.99,0.36,29.16,0.86,27.1,0.53,1,300.25 -2015-02-01,25.59,-0.55,26.55,0.18,29.12,1.02,27.29,0.56,2,300.44 -2015-03-01,26.69,0.06,27.29,0.15,29.32,1.13,27.79,0.58,3,300.94 -2015-04-01,26.95,1.35,28.17,0.67,29.73,1.23,28.56,0.78,4,301.71 -2015-05-01,26.71,2.43,28.28,1.19,29.88,1.09,28.88,1.03,5,302.03 -2015-06-01,25.42,2.54,28.1,1.66,29.93,1.09,28.96,1.32,6,302.10999999999996 -2015-07-01,24.48,2.87,27.79,2.17,29.8,1.0,28.82,1.6,7,301.96999999999997 -2015-08-01,22.88,2.24,27.33,2.34,29.66,0.98,28.89,2.07,8,302.03999999999996 -2015-09-01,22.91,2.57,27.48,2.63,29.73,1.04,29.0,2.28,9,302.15 -2015-10-01,23.31,2.52,27.58,2.66,29.79,1.12,29.15,2.46,10,302.29999999999995 -2015-11-01,23.83,2.24,27.91,2.93,30.3,1.67,29.6,2.95,11,302.75 -2015-12-01,25.01,2.19,27.99,2.85,30.11,1.63,29.39,2.82,12,302.53999999999996 -2016-01-01,25.93,1.41,28.21,2.58,29.65,1.35,29.17,2.6,1,302.32 -2016-02-01,26.81,0.67,28.36,1.99,29.55,1.45,29.12,2.4,2,302.27 -2016-03-01,27.57,0.93,28.7,1.57,29.53,1.34,28.9,1.68,3,302.04999999999995 -2016-04-01,25.83,0.23,28.34,0.84,29.39,0.89,28.87,1.09,4,302.02 -2016-05-01,24.55,0.27,27.11,0.03,29.39,0.6,28.15,0.3,5,301.29999999999995 -2016-06-01,23.17,0.29,26.31,-0.12,29.36,0.52,27.53,-0.12,6,300.67999999999995 -2016-07-01,21.79,0.17,25.14,-0.48,29.06,0.26,26.73,-0.49,7,299.88 -2016-08-01,21.03,0.39,24.53,-0.46,28.68,-0.0,26.28,-0.54,8,299.42999999999995 -2016-09-01,20.87,0.53,24.67,-0.18,28.48,-0.21,26.11,-0.61,9,299.26 -2016-10-01,21.18,0.39,24.47,-0.45,28.26,-0.4,25.96,-0.73,10,299.10999999999996 -2016-11-01,21.68,0.09,24.58,-0.4,28.27,-0.37,26.1,-0.55,11,299.25 -2016-12-01,23.35,0.53,24.78,-0.36,28.35,-0.14,26.16,-0.41,12,299.31 -2017-01-01,25.75,1.23,25.61,-0.02,28.18,-0.12,26.25,-0.32,1,299.4 -2017-02-01,27.76,1.62,27.0,0.63,28.03,-0.07,26.87,0.14,2,300.02 -2017-03-01,28.52,1.89,27.7,0.57,28.13,-0.06,27.34,0.13,3,300.48999999999995 -2017-04-01,26.53,0.93,28.09,0.59,28.65,0.15,28.1,0.32,4,301.25 -2017-05-01,25.06,0.78,27.6,0.51,29.08,0.29,28.3,0.46,5,301.45 -2017-06-01,22.98,0.1,26.73,0.3,29.39,0.55,28.19,0.55,6,301.34 -2017-07-01,21.54,-0.07,25.85,0.23,29.21,0.4,27.61,0.39,7,300.76 -2017-08-01,20.19,-0.45,24.82,-0.17,28.87,0.19,26.67,-0.15,8,299.82 -2017-09-01,19.67,-0.67,24.17,-0.68,28.69,0.0,26.29,-0.43,9,299.44 -2017-10-01,19.45,-1.34,24.28,-0.64,28.55,-0.11,26.23,-0.46,10,299.38 -2017-11-01,20.44,-1.15,23.92,-1.05,28.46,-0.18,25.79,-0.86,11,298.94 -2017-12-01,21.44,-1.38,24.05,-1.09,28.24,-0.25,25.8,-0.77,12,298.95 -2018-01-01,23.71,-0.81,24.48,-1.14,28.03,-0.27,25.82,-0.75,1,298.96999999999997 -2018-02-01,25.57,-0.57,25.36,-1.01,27.86,-0.24,25.83,-0.9,2,298.97999999999996 -2018-03-01,25.83,-0.8,26.37,-0.76,28.14,-0.05,26.48,-0.73,3,299.63 -2018-04-01,24.58,-1.02,27.12,-0.38,28.63,0.12,27.42,-0.36,4,300.57 -2018-05-01,23.73,-0.54,26.94,-0.15,29.01,0.22,27.72,-0.13,5,300.87 -2018-06-01,22.19,-0.69,26.72,0.29,29.16,0.32,27.85,0.2,6,301.0 -2018-07-01,21.43,-0.19,26.05,0.43,29.1,0.3,27.52,0.3,7,300.66999999999996 -2018-08-01,20.66,0.02,25.14,0.15,29.19,0.51,27.11,0.29,8,300.26 -2018-09-01,20.31,-0.03,25.2,0.35,29.17,0.48,27.1,0.38,9,300.25 -2018-10-01,21.23,0.43,25.78,0.86,29.61,0.95,27.55,0.86,10,300.7 -2018-11-01,22.27,0.68,26.02,1.05,29.59,0.95,27.64,0.99,11,300.78999999999996 -2018-12-01,23.6,0.78,26.12,0.98,29.52,1.03,27.53,0.96,12,300.67999999999995 -2019-01-01,25.1,0.57,26.17,0.55,29.0,0.65,27.08,0.52,1,300.22999999999996 -2019-02-01,26.45,0.24,26.91,0.55,29.06,0.86,27.41,0.68,2,300.56 -2019-03-01,26.8,0.07,27.89,0.71,29.1,0.77,28.22,0.95,3,301.37 -2019-04-01,25.68,-0.01,28.17,0.56,29.24,0.56,28.6,0.71,4,301.75 -2019-05-01,24.38,-0.08,27.69,0.51,29.58,0.63,28.57,0.62,5,301.71999999999997 -2019-06-01,22.62,-0.38,26.81,0.27,29.62,0.6,28.24,0.47,6,301.39 -2019-07-01,21.34,-0.33,25.68,-0.07,29.73,0.77,27.63,0.3,7,300.78 -2019-08-01,20.2,-0.46,24.89,-0.15,29.5,0.68,26.97,0.1,8,300.12 -2019-09-01,19.5,-0.83,24.61,-0.23,29.33,0.55,26.7,-0.03,9,299.84999999999997 -2019-10-01,20.02,-0.71,25.12,0.17,29.64,0.88,27.31,0.59,10,300.46 -2019-11-01,21.32,-0.22,25.46,0.41,29.47,0.7,27.26,0.51,11,300.40999999999997 -2019-12-01,23.16,0.4,25.47,0.26,29.5,0.91,27.07,0.43,12,300.21999999999997 -2020-01-01,24.55,0.02,25.81,0.2,29.28,0.93,27.09,0.53,1,300.23999999999995 -2020-02-01,26.56,0.35,26.61,0.24,29.17,0.98,27.14,0.41,2,300.28999999999996 -2020-03-01,27.11,0.38,27.43,0.24,29.22,0.89,27.82,0.55,3,300.96999999999997 -2020-04-01,26.0,0.32,28.01,0.4,29.29,0.61,28.32,0.44,4,301.46999999999997 -2020-05-01,24.24,-0.22,26.82,-0.36,28.94,-0.01,27.59,-0.36,5,300.73999999999995 -2020-06-01,22.13,-0.87,25.75,-0.79,29.07,0.05,27.3,-0.47,6,300.45 -2020-07-01,20.44,-1.23,25.08,-0.66,28.83,-0.13,26.89,-0.44,7,300.03999999999996 -2020-08-01,19.69,-0.97,24.42,-0.62,28.47,-0.35,26.18,-0.69,8,299.33 -2020-09-01,19.48,-0.85,23.58,-1.26,28.29,-0.49,25.77,-0.96,9,298.91999999999996 -2020-10-01,19.67,-1.07,23.61,-1.34,27.89,-0.87,25.3,-1.42,10,298.45 -2020-11-01,20.94,-0.61,23.82,-1.23,27.91,-0.86,25.34,-1.42,11,298.48999999999995 -2020-12-01,22.16,-0.6,24.38,-0.83,27.65,-0.95,25.53,-1.12,12,298.67999999999995 -2021-01-01,23.89,-0.64,25.06,-0.55,27.1,-1.25,25.58,-0.99,1,298.72999999999996 -2021-02-01,25.55,-0.66,25.8,-0.57,27.2,-1.0,25.81,-0.92,2,298.96 -2021-03-01,26.48,-0.26,26.8,-0.39,27.79,-0.55,26.75,-0.51,3,299.9 -2021-04-01,24.89,-0.8,26.96,-0.65,28.47,-0.21,27.4,-0.49,4,300.54999999999995