Introduction to Recommender Systems

<button class="btn btn-link bookmark-button "
aria-pressed="false"
data-bookmark-id="NoahB,block-v1:IRONHACK+DAFT+201906_MIA+type@vertical+block@798975c30b174a6baaec88f9622e071f"
data-bookmarks-api-url="/api/bookmarks/v1/bookmarks/">
Bookmark this page
</button>

Lesson Goals

Learn about recommender systems.

Define collaborative filtering.

Visualize user ratings across preference space.

Calculate user similarities across all preference spaces.

Use similarity scores to weight ratings.

Rank weighted ratings to produce recommendations.

Introduction

Recommender systems are a foundational part of the digital world today. They are used to personalize the experience a user has with a website or application, thus making it more useful to the user. Some of today's most prominent companies have recommender systems at the core of the customer experience.

Amazon recommends you products based on past product purchases, ratings, and the purchases/ratings of other customers similar to you.

Netflix recommends you movies based on the movies you've watched, your rating of movies, and the behavior of other users similar to you.

Facebook, Twitter, & LinkedIn recommend people you might know based on your connections and the connections of those you are connected to and also use this information to personalize your newsfeed.

In this lesson, we will learn the fundamentals of recommender systems, how they work, and how to create a basic user-based filtering system using Python.

Collaborative Filtering

Before recommender systems existed, the primary way to get recommendations about things like movies or products was to ask your friends. As you followed recommendations from them, you would get a sense of which friends had tastes that were most similar to yours and rely on their recommendations more frequently. However, as the number of options available to us has increased drastically over the last few decades, it became increasingly difficult to rely on recommendations from a small group of friends because it also became increasingly likely that they were not aware of all the available options. The solution for this was a method called collaborative filtering.

Collaborative filtering provides us with a way of making automatic predictions (filtering) about the interests of a user by collecting preferences from many users (collaborating). The underlying assumption is that if two people have the same opinion on one issue, they are likely to have a similar opinion on other issues as well. There are a few different ways to approach collaborative filtering, but generally speaking, they involve finding a group of people similar to a user, analyzing the things they like, and coming up with a ranked list of recommendations for the user.

User Similarity

User similarity is at the heart of collaborative filtering. In order to make good recommendations, we need to know how alike two users are. The way to do this is by comparing how similar their ratings for the same product have been. For example, let's import the movie_ratings.csv file.

import pandas as pd
ratings = pd.read_csv('movie_ratings.csv').set_index('Movie')

This data frame contains 10 movies and ratings from 5 users on a scale from 1 (they didn't like it) to 5 (they loved it).

If we wanted to take a look at their user ratings across the preference space of two movies, we could define a function that accepts two movie titles and scatter plots the user ratings as follows.

def ratings_scatter(movie1, movie2):
x = ratings.T[movie1]
y = ratings.T[movie2]
n = list(ratings.T.index)
fig, ax = plt.subplots()
ax.scatter(x, y, s=0)
fig.set_figwidth(12)
fig.set_figheight(8)
plt.title("Preference Space for "+ movie1 + " vs. " + movie2, fontsize=20)
ax.set_xlabel(movie1, fontsize=16)
ax.set_ylabel(movie2, fontsize=16)
for i, txt in enumerate(n):
ax.annotate(txt, (x[i], y[i]), fontsize=12)

Then, we would just need to choose two titles and generate the plot to visualize the preference space for users across those two movies. For example, below is the preference space across the movies Venom and Incredibles 2.

ratings_scatter('Venom', 'Incredibles 2')

<img src="https://camo.githubusercontent.com/2105bc4488ebfeb4f759fd7d3cf0f43a851e1d84/68747470733a2f2f73332d65752d776573742d312e616d617a6f6e6177732e636f6d2f69682d6d6174657269616c732f75706c6f6164732f646174612d7374617469632f696d616765732f707265666572656e63652d73706163652d76656e6f6d2d696e6372656469626c65732e706e67" alt="Preference Space Venom Incredibles" data-canonical-src="https://s3-eu-west-1.amazonaws.com/ih-materials/uploads/data-static/images/preference-space-venom-incredibles.png" style="max-width:100%;">

We can see that across this preference space, Rusty is more similar to Brandon than he is Emily. However, this can vary across different sets of movies. If we instead scatter plot the ratings for Bohemian Rhapsody and Jurassic World, Rusty is more similar to Emily than to Brandon in this preference space.

ratings_scatter('Bohemian Rhapsody', 'Jurassic World: Fallen Kingdom')

<img src="https://camo.githubusercontent.com/d394cc98f142490bab332b7cfc57f395441c4ec4/68747470733a2f2f73332d65752d776573742d312e616d617a6f6e6177732e636f6d2f69682d6d6174657269616c732f75706c6f6164732f646174612d7374617469632f696d616765732f707265666572656e63652d73706163652d626f68656d69616e2d6a757261737369632e706e67" alt="Preference Space Bohemian Jurassic" data-canonical-src="https://s3-eu-west-1.amazonaws.com/ih-materials/uploads/data-static/images/preference-space-bohemian-jurassic.png" style="max-width:100%;">

To get the aggregate distance across all the preference spaces, we can use squareform and pdist from the Scipy library to create a matrix containing the Euclidean distances between all our users.

from scipy.spatial.distance import pdist, squareform
squareform(pdist(ratings.T, 'euclidean'))
array([[0., 6.63324958, 6., 7.41619849, 7.48331477],
[6.63324958, 0., 6.92820323, 6.40312424, 5.09901951],
[6., 6.92820323, 0., 5.56776436, 8.24621125],
[7.41619849, 6.40312424, 5.56776436, 0., 6.70820393],
[7.48331477, 5.09901951, 8.24621125, 6.70820393, 0. ]])

These distances are smaller for users that are more similar, but for our purposes it would be preferable to have a higher score for users that are more similar and a lower score for users that are less similar. We can easily achieve this by adding 1 to the scores and inverting them. Let's also import them into a data frame so that we can more easily view and analyze them.

distances = pd.DataFrame(1/(1 + squareform(pdist(ratings.T, 'euclidean'))),
index=ratings.columns, columns=ratings.columns)
distances

Generating Recommendations for a User

Suppose that we had a new user named Tom who came to us with the following ratings for each movie.

tom = {'Aquaman': 2,
'Avengers: Infinity War': 1,
'Black Panther': 5,
'Bohemian Rhapsody': 5,
'Deadpool 2': 2,
'Fantastic Beasts: The Crimes of Grindelwald': 3,
'Incredibles 2': 3,
'Jurassic World: Fallen Kingdom': 4,
'Mission: Impossible вЂ“ Fallout': 3,
'Venom': 3}

We could factor Tom into our similarity matrix and then determine which other users are most similar to him.

ratings['Tom'] = pd.Series(tom)
distances = pd.DataFrame(1/(1 + squareform(pdist(ratings.T, 'euclidean'))),
index=ratings.columns, columns=ratings.columns)
similarities = distances['Tom'].sort_values(ascending=False)[1:]
similarities
Cleo 0.217129
Brandon 0.156613
Emily 0.135078
Rusty 0.126132
Samantha 0.116961
Name: Tom, dtype: float64

It looks like Cleo is the user that is most similar to Tom, followed by Brandon, Emily, Rusty, and then Samantha. These similarity scores should be taken into consideration when recommending movies to Tom that he has not yet seen.

Let's say that everyone but Tom also rated the movies in the movie_ratings2.csv file. Let's import those ratings and then combine them with the similarity scores to generate movie recommendations to Tom.

new_ratings = pd.read_csv('movie_ratings2.csv').set_index('Movie')

Once we have our new_ratings data frame, we are going to copy it to a new recommendations data frame which we will perform our calculations on.

recommendations = new_ratings.copy()

We are going to iterate through each of the other users' similarity scores with Tom and weight their recommendations of these new movies by their similarity score. We are then going to create a new Total column that sums up the total scores for each movie and sort on that so that the movies are in the order that they should be recommended to Tom.

for name, score in dict(similarities).items():
recommendations[name] = recommendations[name] * score
recommendations['Total'] = recommendations.sum(axis=1)
recommendations.sort_values('Total', ascending=False)

From these results, it looks like Tom should like Despicable Me 3, Wonder Woman, and Thor but perhaps not Star Wars or The Fate of the Furious.

Using Different Similarity Metrics

Now that we have generated an initial set of recommendations, there is an important topic we would like to circle back and discuss. When we computed our user similarity metrics, we used Euclidean distance as our distance metric. It is important to note that there are a number of other distance metrics in Scipy that we could potentially use to get different results. A full list of all the ones available can be found here.

To see what the recommendations look like using a different distance metric, all we need to do is swap out the name if the metric in the first line of code below. For example, if we wanted to use cosine distance instead, the results would look like this.

distances = pd.DataFrame(1/(1 + squareform(pdist(ratings.T, 'cosine'))),
index=ratings.columns, columns=ratings.columns)
similarities = distances['Tom'].sort_values(ascending=False)[1:]
recommendations = new_ratings.copy()
for name, score in dict(similarities).items():
recommendations[name] = recommendations[name] * score
recommendations['Total'] = recommendations.sum(axis=1)
recommendations.sort_values('Total', ascending=False)

We can see that Wonder Woman is now at the top of the list, Guardians of the Galaxy dropped a few places, and Wolf Warrior crept up to the number 4 spot.

If we tried cityblock distance instead, Guardians of the Galaxy shoots up to the number 3 spot and Spider-Man creeps up into the top 5.

Try some of the other distance metrics and note the impact on the rankings.

Summary

In this lesson, we provided an introduction to recommender systems and took a look at how we could create a user-based filtering recommender. Along the way, we visualized user preference spaces for pairs of movies, calculated similarity scores between groups of users, and combined those similarity scores with ratings to rank movies so that we could recommend them to a particular user. This is just the tip of the iceberg when it comes to recommender systems, but hopefully this lesson gave you a sense of how these types of systems work and how you might put one together of your very own.

Survival Analysis

<button class="btn btn-link bookmark-button "
aria-pressed="false"
data-bookmark-id="NoahB,block-v1:IRONHACK+DAFT+201906_MIA+type@vertical+block@057ece429ce94b2d8844f86b4ba1f7c2"
data-bookmarks-api-url="/api/bookmarks/v1/bookmarks/">
Bookmark this page
</button>

Lesson Goals

Introduce survival analysis

Introduce Kaplan-Meier estimates

Perform survival analysis on event data

Visualize and compare survival curves

Perform survival analysis for cohorts from different perspectives

Introduction

Survival analysis is an important topic in analytics that rarely receives the coverage it deserves. As the name implies, it was originally developed to quantify and measure the lifespans of individuals (how likely someone was to die or survive). For example, if you wanted to know what the probability of death over time was for a certain a group of people who had contracted some illness, you would use survival analysis. However, the techniques used in survival analysis can be applied to a wide variety of situations.

In this lesson, we are going to cover the basics of survival analysis so that you can leverage this valuable set of techniques in analyses that you conduct going forward. To do this, we will need to install a new Python library called lifelines that is specifically used for conducting survival analysis.

$ pip install lifelines

We will import the components of lifelines a little later as we need them. We are also going to be using Pandas in this lesson as well as Plotly and Cufflinks, so let's go ahead and import those.

import pandas as pd
import plotly.plotly as py
import cufflinks as cf
cf.go_offline()

Survival Analysis

Survival analysis can be performed on various scenarios:

Estimating human lifespans

Estimating mechanical failures over time

Estimating length of customer retention

Estimating time to recovery for illnesses

There are certain requirements for conducting a survival analysis. The first of these is that you need to have a field in your data that represents the occurrence (or lack thereof) of an event.

The second requirement is that you need to have a field that represents the passage of time in some fashion. This can be datetimes or it can be a number that increases with the passage of time, such as number of days/weeks/months/years, the number of uses, distance traveled, etc.

The third and final requirement is that you need to have at least one field to group by. Survival analysis calculates the survival rates for groups that something in common. The group by field is the thing they have in common. If you have multiple fields you can group by, you can perform the analysis for the groups represented by each field individually or you can combine them into more granular segments and examine the survival rates of those. However, you can only do this up to a point where the number of examples in a group become too few to reliably calculate their survival rates. So you need to balance the ability drill down into granular details with the need to have large enough groups to calculate meaningful and reliable survival rates.

The Data

The data we will be working with in this lesson will be the customer churn data set from previous lessons. This data meets all three of our criteria above. It contains an event field (ChurnBinary) that indicates whether or not a customer has churned. It contains a field that represents the passage of time (tenure). And finally, it contains several categorical fields by which we can group customers so that we can explore their retention rates from different perspectives.

Let's go ahead and import the data which you can download here.

data = pd.read_csv('churn.csv')

Performing a Survival Analysis

Now that we have identified the data we want to use and the corresponding fields, we can begin our analysis. The objective of our analysis is going to be to get a sense of the decline in customer retention rates as tenure increases among the different groups of customers we have in our data set.

The easiest way to do this in Python is with the lifelines library. We are going to import the KaplanMeierFitter from lifelines. Kaplain-Meier curves are one of the most common statistical techniques used in survival analysis, and they will help us estimate the survival function of the different cohorts we designate (e.g. males vs. females, senior citizens vs. non-seniors, etc.).

from lifelines import KaplanMeierFitter

From there, we are going to define a survival function that is going to accept a data frame and then specify each of the three necessary components for conducting a survival analysis (a group field, a time field, and an event field). Within the function, we are going to define our model and then create an empty list in which we are going to store our results. From there, we loop through the each of the unique values in the group field, grab the data in the time and event fields, fit our model to the data, and append the survival function results to our results list. At the end, we concatenate the data for each unique group field value together and then return those results.

def survival(data, group_field, time_field, event_field):
model = KaplanMeierFitter()
results = []
for i in data[group_field].unique():
group = data[data[group_field]==i]
T = group[time_field]
E = group[event_field]
model.fit(T, E, label=str(i))
results.append(model.survival_function_)
survival = pd.concat(results, axis=1)
return survival

Once we have this function, it is relatively easy to generate survival curves for any of the cohorts in our data set. For example, if we wanted to visualize retention rates over time by gender, we could do that with just a couple lines of code.

rates = survival(data, 'gender', 'tenure', 'ChurnBinary')
rates.iplot(kind='line', xTitle='Tenure (Months)', yTitle='Retention Rate',
title='Retention Rates by Tenure and Gender')

We can see that at tenure 0, both survival curves start at 1 (100%). The female curve then declines a little faster than the male curve and then they both continue to decline gradually until they get past 60 months, at which point the male curve takes a steeper dive below the female retention rates. Both curves end at around the 60% mark, meaning that after 70 months of tenure, a customer is approximately 40% likely to churn (60% retention rate).

Using our function, we can easily swap out group fields to take a look at survival rates form different perspectives. Here are the survival curves for senior citizens and non-seniors.

rates = survival(data, 'SeniorCitizen', 'tenure', 'ChurnBinary')
rates.iplot(kind='line', xTitle='Tenure (Months)', yTitle='Retention Rate',
title='Retention Rates by Tenure and Senior Citizen')

From this perspective, we can see that the survival curve for senior citizens has a steeper slope than the curve for non-seniors, which causes them to end up with a much lower retention rate than non-seniors.

What if we define our cohorts around the type of Internet service the customer has as opposed to demographics?

rates = survival(data, 'InternetService', 'tenure', 'ChurnBinary')
rates.iplot(kind='line', xTitle='Tenure (Months)', yTitle='Retention Rate',
title='Retention Rates by Tenure and Internet Service')

From this perspective, we can see that customers without Internet service tend to have higher retention rates than ones who do. Among the ones that do have Internet service with the company, the ones that have DSL have much higher retention rates compared to the ones that have fiber optic, perhaps because the latter tends to be significantly more expensive.

The company also provides customers with the option of signing up for one year or two year contracts as opposed to just paying for their services month-to-month. Let's see how the survival curves look for each of those three options.

rates = survival(data, 'Contract', 'tenure', 'ChurnBinary')
rates.iplot(kind='line', xTitle='Tenure (Months)', yTitle='Retention Rate',
title='Retention Rates by Tenure and Senior Citizen')

As you probably expected, the customers on two year contracts have the highest retention rates, even well past the 24 month (2 year) mark. Customers on one year contracts have high retention rates until about 40 months out, and then the rate at which they churn increases. And finally, the customers who pay month-to-month start churning almost right away with a very steep decline in retention between 0 and 10 months and then leveling off slightly but still pretty steep.

Usefulness of Survival Analysis

As we saw above, survival analysis is useful for deriving insights about what factors matter most when you have event data over time. In our case, we were able to observe the survival curves estimating what percentage of customers the company would retain and what percentage are likely to churn over time from varying perspectives.

This is useful to companies, as it allows them estimate when a customer is most likely to cancel their service. The company could then determine the appropriate time to intervene and offer the customer either a discounted upgrade or a lower price on the service they currently have (perhaps tied to a one or two year contract) to prevent them from leaving and thus increasing their retention rates.

Summary

In this lesson, we covered the basics of survival analysis in Python. We introduced the lifelines library as well as Kaplan-Meier curves and then we used them to fit model to the group, event, and time data we had to generate survival functions for each cohort. We performed this analysis from several different perspectives to get a good sense of what factors have the most influence on churn rates.

Time Series Analysis

<button class="btn btn-link bookmark-button "
aria-pressed="false"
data-bookmark-id="NoahB,block-v1:IRONHACK+DAFT+201906_MIA+type@vertical+block@a9e0c9c70f7342e485991e2fe5928d5c"
data-bookmarks-api-url="/api/bookmarks/v1/bookmarks/">
Bookmark this page
</button>

  Lesson Goals

In this lesson we will discover the branch of statistics that deals with time ordered data, also known as time series. We will learn about the different types of time series, about correlation and auto-correlation, and about different prediction methods for time series data.

  Introduction

So far we have studied data that is static in time. This was important since many models require that we assume that observations are independent of one another. However, when dealing with time ordered data, many times this assumption is no longer valid. For example, the temperature observed today is not independent of the temperature yesterday. Another example is the stock market. Today's stock prices are related to yesterday's stock prices. In this lesson we will explore how to deal with data that contains such relationships

  Time Series Decomposition

One of the ways to overcome the issues caused by having a relationship between the observations is to decompose the data into components. Typically, we split the data into two types of components - systematic and non-systematic.

Systematic components are components that can have consistency or recurrence.

Non-systematic components cannot be modeled.

We can typically decompose a time series into 4 components - 3 systematic components and one noise component.:

The mean of the series

The seasonality or cyclical pattern of the series

The trend of the series - this component is what we would like to model

The noise is typically the random variation in our data

  Time Series Decomposition in Python

We will focus on the statsmodels library for modeling and plotting time series data in Python. statsmodels contains a function called seasonal_decompose that will allow us to plot the decomposed time series data.

For our example, we will use the occupancy dataset.

occupancy = pd.read_csv('occupancy.csv')
occupancy.head()
date Temperature Humidity Light CO2 HumidityRatio Occupancy
0 2/2/2015 14:00 23.7000 26.272 585.200000 749.200000 0.004764 1
1 2/2/2015 15:00 23.7180 26.290 578.400000 760.400000 0.004773 1
2 2/2/2015 16:00 23.7300 26.230 572.666667 769.666667 0.004765 1
3 2/2/2015 17:00 23.7225 26.125 493.750000 774.750000 0.004744 1
4 2/2/2015 18:00 23.7540 26.200 488.600000 779.000000 0.004767 1

To plot this data, we must make sure our index is a time series with a known frequency. To analyze time series data, the data needs to be equally spaced. In the code below, we will change the type of the date column to datetime and change the index to the date column. Our frequency is 1 hour. Even though we can see that the difference between observation is 1 hour, it is not inferred, and we need to specify it ourselves. To read more about frequencies, look here.

occupancy.date = pd.to_datetime(occupancy.date)
occupancy.index = pd.DatetimeIndex(occupancy.date, freq='H')
occupancy.index
DatetimeIndex(['2015-02-02 14:00:00', '2015-02-02 15:00:00',
'2015-02-02 16:00:00', '2015-02-02 17:00:00',
'2015-02-02 18:00:00', '2015-02-02 19:00:00',
'2015-02-02 20:00:00', '2015-02-02 21:00:00',
'2015-02-02 22:00:00', '2015-02-02 23:00:00',
...
'2015-05-24 04:00:00', '2015-05-24 05:00:00',
'2015-05-24 06:00:00', '2015-05-24 07:00:00',
'2015-05-24 08:00:00', '2015-05-24 09:00:00',
'2015-05-24 10:00:00', '2015-05-24 11:00:00',
'2015-05-24 12:00:00', '2015-05-24 13:00:00'],
dtype='datetime64[ns]', name='date', length=2664, freq='H')

Now we can plot the decomposed time series.

import statsmodels.api as sm
res = sm.tsa.seasonal_decompose(occupancy.CO2)
resplot = res.plot()

  Autoregression

An autoregressive model is a model that uses previous observations in the time series to predict the next value in the model. In previous lessons, we have looked at linear models where the response variable depends only on the predictor variables and the linear regression equation is of the form:

However, when working with time series data, our response variable depends not only on the predictor variables but also on the response variable itself. A variable that depends on itself is called an autocorrelated variable. Typically, our regression equation will be of the form below. The equation below is an autoregressive model that depends only on the previous time period.

Our model can also depend on more than one time period in the past.

  Checking for Autocorrelation

We can check for autocorrelation in our data using a lag plot. This plot will plot y t against y t-1. Pandas has a function called lag_plot for detecting these relationships.

from pandas.tools.plotting import lag_plot
lag_plot(occupancy.CO2)

A line along the diagonal shows that there is an autoregressive relationship.

To create an autoregressive model we use the AR function. Typically, we note an autoregressive model with the notation AR(n) where n is the number of lag periods. In the example below, we will create an autoregressive model with lag 1 to model the rate of CO2. In the example below, we limit the lag periods to 1. However, if we do not set a limit, the model may contain more lag periods.

Note that we split the data into test and train and always use the last few observations when working with time series data. We do this to ensure that the model gives good predictions even on data it has not seen. Since the data is ordered, we cannot select the test data at random.

from statsmodels.tsa.ar_model import AR
train, test = occupancy.CO2[:-10], occupancy.CO2[-10:]
model = AR(occupancy.CO2)
model_fit = model.fit(maxlag=1)
predictions = model_fit.predict(start=len(train), end=len(train)+len(test)-1, dynamic=False)

Like linear regression, this model produces coefficients for the autoregressive model as well as predictions.

print(model_fit.params)
const 0.001078
L1.CO2 1.000195
dtype: float64
pd.DataFrame({'observed':test, 'predicted':predictions})
observed predicted
date
2015-05-24 04:00:00 1153.250000 1152.725379
2015-05-24 05:00:00 1152.400000 1153.475525
2015-05-24 06:00:00 1146.166667 1152.625359
2015-05-24 07:00:00 1145.400000 1146.390813
2015-05-24 08:00:00 1140.800000 1145.623997
2015-05-24 09:00:00 1150.250000 1141.023102
2015-05-24 10:00:00 1129.200000 1150.474941
2015-05-24 11:00:00 1125.800000 1129.420844
2015-05-24 12:00:00 1123.000000 1126.020182
2015-05-24 13:00:00 1124.000000 1123.219637

  Stationarity

A time series is considered stationary if its mean and variance do not vary over time. While we cannot consider a stationary time series to be independent, stationarity is a dependence structure that can help us with a number of modeling techniques. To check whether we have a stationary time series, we can either examine the decomposition plot visually, compute the mean and standard deviation over time, or use statistical tests. One possible test is the Augmented Dickey-Fuller test. This test has the following hypothesis:

H 0: The data is not stationary

H 1: The data is stationary

We test stationarity using the adrfuller function in statsmodels. The example below demonstrates this with our CO2 data. The adrfuller function returns multiple values. The second position in the data structure returned is the p-value of our hypothesis.

from statsmodels.tsa.stattools import adfuller
adfuller(occupancy.CO2)[1]
0.06822624483241028

The p-value is greater than 0.05. Therefore, with a 95% confidence interval, we do not reject the null hypothesis and conclude that the data is not stationary.

  Random Walks

A random walk is a type of time series model where each observation depends on the sum of the previous observation and a random noise component. The formal notation for this is:

Random walks are considered non-stationary because the covariance between observations is time dependent.

  Moving Average

Moving average models are similar to autoregressive models. Moving average models also depend on a linear combination of past data. However, unlike autoregressive models, these models depend on past white noise terms. While the name is the same, moving average models are not the same as calculating the moving average of a time series.

Moving average models are typically noted with MA(q) where q is the number of past white noise terms summed by the model. For example, a first order moving average model will be noted by:

Note that the errors are normally distributed with mean 0 and variance σ ω.

We can create a moving average model using the ARMA function in the statsmodels package. This function generates models that can have both an autoregressive component as well as a moving average component. However, here we will set the autoregressive lag to zero to create only a moving average model. Let's use our CO2 data again for this example.

from statsmodels.tsa.arima_model import ARMA
model = ARMA(occupancy.CO2, order=(0, 1))
model_fit = model.fit(disp=False)
predictions = model_fit.predict(len(occupancy.CO2)-3, len(occupancy.CO2)-1)

Let's look at the predictions:

pd.DataFrame({'observed':occupancy.CO2[-3:], 'predicted':predictions})
observed predicted
date
2015-05-24 11:00:00 1125.8 926.765185
2015-05-24 12:00:00 1123.0 915.381418
2015-05-24 13:00:00 1124.0 923.899751

We can see that this model alone is not a great fit for this data since there is a big difference between observed and predicted.

  Combining Autoregression with Moving Average

As we have seen in the previous paragraph, we can create a model with both an autoregressive component and a moving average component. This model is called an ARMA model and is denoted by ARMA(n, q) where n is the number of lag periods and q is the number of past white noise terms. Below is an example of an ARMA model with two lag terms and one white noise term.

from statsmodels.tsa.arima_model import ARMA
# fit model
model = ARMA(occupancy.CO2, order=(2, 1))
model_fit = model.fit(disp=False)
# make prediction
predictions = model_fit.predict(len(occupancy.CO2)-3, len(occupancy.CO2)-1)

We expect our predictions to improve:

pd.DataFrame({'observed':occupancy.CO2[-3:], 'predicted':predictions})
observed predicted
date
2015-05-24 11:00:00 1125.8 1128.220466
2015-05-24 12:00:00 1123.0 1124.658200
2015-05-24 13:00:00 1124.0 1121.741400

  Conclusion

In this lesson we were introduced to a number of basic concepts in time series modeling. Time series models require different treatment than linear models. We learned about the different components of a time series and how to plot them. We learned about stationarity, random walks, and autoregressive and moving average models. This introduction should provide you with the tools to evaluate and model time ordered data.


4 Egregious Aggregations
Once armed with an understanding of the data and tools available for analysis, a common start to analysis is exploring data with aggregation. At its heart, any sort of data analysis is the process of condensing raw data into something more manageable and useful while giving up as little of the information as possible.
Many elementary tools for this task are much better at the comprehension task than the preservation one. We learn rigorous assumptions to consider and validate when studying linear regression, but basic arithmetic aggregation presents itself as agnostic and welcome to any type of data. However, the underlying distributions of our variables and the relationships between them have a significant impact on the how informative and interpretable various summarizations are.
In this chapter, we will explore different ways that univariate and multivariate aggregations can be naive or uninformative.
4.1 Averages
4.1.1 Averaging skewed data
Arithmetic average versus colloquial meaning of average as “typical”
Skewed data
Multimodal data / mixture models
4.1.2 No “average” observation
In the previous section, the average represented a point in the relevant data range even if it was not perhaps the one most representative of a “typical” observation. We discussed how in some situations this quantity may be a reasonable answer to certain types of questions and an aid for certain types of decisions.
However, when we seek an average profile over multiple variables, the problems of averages are further compounded. We may end up with a set of “average” summary statistics that are not representative of any part of our population.
To see this, let’s assume we are working with data for a company with a subscription business model. We might be interested in profiling the age of each account (how long they have been a subscriber) and their activity (measured by amount spent on an e-commerce platform, files downloaded on a streaming service, etc.)
The following code simulates a set of observations: 80% of accounts are between 0 to 3 years in age and have an average activity level of 100 while 20% of accounts are older than 3 years in age and have an average activity level of 500. (Don’t over-think the specific probability distributions lived here. We are concerned with interrogating the properties of the average and not with simulating a realistic data generating process. Giving ourselves permission to be wrong or “lazy” about unimportant things gives us more energy to focus on what matters.)
set.seed(123)
# define simulation parameters ----
## n: total observations
## p: proportion of observations in group 1
n <- 5000
p <- 0.8
n1 <- n*p
n2 <- n*(1-p)
# generate fake dataset with two groups ----
df <-
data.frame(
age = c(runif(n1, 0, 3), runif(n2, 3, 10)),
act = c(rnorm(n1, 100, 10), rnorm(n2, 500, 10))
)
Figure 4.1 shows a scatterplot of the relationship between account age (x-axis) and activity level (y-axis). Meanwhile, the marginal rug plots shows the univariate distribution of each variable. The sole red dot denotes the coordinates of the average age and average activity. Notably, this dot exists in a region of “zero density”; that is, it is not representative of any customer. Strategic decisions made with this sort of observation in mind as the “typical” might not be destined for success.
4.1.3 The product of averages
As the above example shows, averages of multivariate data can produce poor summaries – particularly when these variables are interrelated14.
A second implication of this observation is that deriving additional computations based on pre-averaged numbers is likely to obtain inaccurate results.
For example, consider that we wish to estimate the average dollar amount of returns per any e-commerce order. Orders may generally be a mixture of low-price orders (around $50 on average) and high-price orders (around $250 on average). Low-price orders may have a 10% probability of being returned while high price orders have a 20% probability. (Again, are these numbers, distributions, or relationships hyper-realistic? Not at all. However, once again we are telling ourselves a story just to reason about numerical properties, so we have to give ourselves permission to not focus on irrelevant details.)
set.seed(123)
# define simulation parameters ----
## n: observations per group
## pr[1|2]: mean price per group
n <- 100
pr1 <- 50
pr2 <- 250
pr_sd <- 5
re1 <- 0.1
re2 <- 0.2
# simulate spend amounts and return indicatiors ----
amt_spend <- c(rnorm(n, pr1, pr_sd), rnorm(n, pr2, pr_sd))
ind_return <- c(rbinom(n, 1, re1), rbinom(n, 1, re2))
# compute summary statistics ----
average_of_product <- mean(amt_spend * ind_return)
product_of_average <- mean(amt_spend) * mean(ind_return)
The true average amount returned across all of our orders is 36.0438 (from the average_of_product
variable).
However, if instead we already knew an average spend amount and an average return proportion, we might be inclined to compute the product_of_average
method which returns a value of 26.9923.
(This is a difference of 9.05 relative to an average purchase amount of 150.)
At first, this may seem unintuitive until we write out the formulas and realize that these metrics are, in fact, two very different quantities:
\[ \frac{ \sum_{1}^{n} Spend }{\sum_{1}^{n} 1} \ * \frac{ \sum_{1}^{n} I(Return) }{\sum_{1}^{n} 1} \] over all \(n\) orders
versus
\[ \frac{\sum_{1}^{n} Spend * I(Return)}{\sum_{1}^{n} 1} \]
If this still feels counterintuitive, we can see how much of the difference is accounted for by the interrelation between our two variables.
In the following code, we break the relationship between the variables by randomly reordering the ind_return
variable so it is no longer has any true relationship to the corresponding amt_spend
variable.
# randomly reorder one of two variables to break relationships ----
ind_return <- sample(ind_return, size = 200)
# recompute variables ----
average_of_product <- mean(amt_spend * ind_return)
product_of_average <- mean(amt_spend) * mean(ind_return)
After redoing the calculations, we find that th two values are much closer.
average_of_product
is now 24.1041 and product_of_average
is now 26.9923.
These are notably still not the same number so that does not mean that these two equations are equivalent if variables are unrelated;
however, this second result once again illustrates the extent to which interrelations can defy our naive intuitions.


Name: Frank Age: 12 Security questions: One Two Street: 123 Main St. City: Springfield State: IL Zipcode: 00000


Rallying: Ogier quits Citroen prompting French team to pull out of WRC
PARIS: Six-time world rally champion Sebastien Ogier has quit Citroen after just one year of his contract, prompting the French constructor to announce on Wednesday (Nov 20) that it is withdrawing from the World Rally Championship (WRC).
"Following the decision of @SebOgier to leave Citroen Racing after 2019 World Rally Championship season, @Citroen decided to withdraw from its @OfficialWRC programme in 2020 due to the absence of a first-class driver available for 2020 season," the team tweeted.
The Frenchman, who won the title every year from 2013 to 2018, has been linked heavily with a move to Toyota who have just seen 2019 world champion Ott Tanak leave for Hyundai.
Ogier joined Citroen on a two-year contract at the start of the 2019 season with the aim of securing a seventh successive title.
However, he could only finish third as Tanak broke a French stranglehold on the title that stretched back 15 years with Sebastien Loeb winning nine before Ogier took up the mantle.
Ogier had previously driven for Citroen between 2008 and 2011 when he left amid tensions with his teammate Loeb.
Citroen have won eight WRC constructors titles, most recently in 2012 and nine drivers' titles, all through Loeb.
After a year away from the WRC in 2016, Citroen returned in 2017 but have won just six out of 40 races since.
Their exit may also be linked to the return of their Groupe PSA stablemate Peugeot to the World Endurance Championship in 2022.


Railway meal service
Our Menu
CHOOSE THE DISH TYPE:
Chettinad non-veg soup
soup veg
soup veg/non-veg
starters- nonveg
Barbecue
Starters- veg
Meals
Dum Biryani varieties
Rice & Noodles
Chicken Special
Chinese special chicken
Lamb special
Sea food- Prawn
Sea food-Crab
Sea food- fish
Egg
Vegeterian
Salads & Papads
ORDER NOW


UXL Object Mapper
| Build Status | Statements | Branches | Functions | Lines |
|---|---|---|---|---|
Installation
npm i @uxland/object-mapper
Usage
A serializer is composed by:
from
: property of input object to serializeto
(optional): destination property to which input object property defined infrom
will be serializedserializerFn
(optional): serialization function used to serialize input followingoutput[to] = serializerFn(input[from])
deserializerFn
(optional): deserialization function used to deserialize output followinginput[from] = deserializerFn(output[to])
Object serialization
from
and to
properties can be a property name or a path.
const input = {foo: 'bar'};
const serializers = [{from: 'foo', to: 'FOO'}];
serialize(input, serializers); // {FOO: 'bar'};
const input = {foo: {baz: 'bar'}};
const serializers = [{from: 'foo.baz', to: 'FOO'}];
serialize(input, serializers); // {FOO: 'bar'};
to
property is optional. When not provided, destination property will be the same as the origin:
const input = {foo: 'bar', qux: 'quz'};
const serializers = [{from: 'foo', to: 'FOO'}, {from: 'qux'}];
serialize(input, serializers); // {FOO: 'bar', qux: 'quz'}
Changing data
serializerFn
is used to change input data
const input = {foo: 'bar'};
const serializers = [{from: 'foo', serializerFn: value => value.toUpperCase()}];
serialize(input, serializers); // {foo: 'BAR'};
Multidestination serialization
to
property can be used to map input data into multiple output properties
const input = {foo: 'bar'};
const serializers = [{from: 'foo', to: ['baz', 'qux']}];
serialize(input, serializers); // {baz: 'bar', qux: 'bar'};
Multiorigin serialization
When defining from
as a property array, and to
as a single property, a serializerFn
must be provided in order to merge input data into a single output
const input = {name: 'foo', surname: 'bar'};
const serializers = [{from: ['name', 'surname'], to: 'fullname', serializerFn: (name, surname) => `${name} ${surname}`}];
serialize(input, serializers); // {fullname: 'foo bar'};
Sub-serialization
Due to its recursive capability, it is possible to define serializers within serializers in order to serialize nested objects
const input = {foo: [{qux: 'quz', bar: 'baz'}]};
const serializers = [{from: 'foo', to: 'FOO', serializers: [{from: 'qux', to: 'QUX'}, {from: 'bar', to: 'BAR'}]}];
serialize(input, serializers); // {FOO: [{QUX: 'quz', BAR: 'baz'}]};
const input = {foo: {qux: 'quz', bar: 'baz'}};
const serializers = [{from: 'foo', to: 'FOO', serializers: [{from: 'qux', to: 'QUX'}, {from: 'bar', to: 'BAR'}]}];
serialize(input, serializers); // {FOO: {QUX: 'quz', BAR: 'baz'}};
Deserialization
It is possible to use the same serializers array to deserialize output. There are some exceptions that are listed in TIC.
const input = {name: 'foo', surname: 'bar'};
const serializers = [{from: ['name', 'surname'], to: 'fullname', serializerFn: (name, surname) => `${name} ${surname}`, deserializerFn: (fullname) => fullname.split(' ')}];
const output = serialize(input, serializers); // {fullname: 'foo bar'};
deserialize(output, serializers); // {name: 'foo', surname: 'bar'}
TIC
One premise must be followed when using the same serializers array for serialize
and deserialize
: you cannot change serialize
object result structure if deserialization
is going to be used.
Also, be aware that changing input structure with serialize
can cause inconsistencies and deserialization could be impossible since serializerFn and deserializerFn cannot access parent data information
Working example
const input = {foo: {baz: 'bar'}};
const serializers = [{from: 'foo.baz', to: 'baz'}];
const output = serialize(input, serializers); // {baz: 'bar'};
deserialize(output, serializers); // {foo: {baz: 'bar'}};
Serialization broken
const input = {foo: 'bar'};
const serializers = [{from: 'foo', serializers: [{from: 'bar'}]}];
const output = serialize(input, serializers); // {foo: {bar: undefined}};
// This cannot be deserialized


This example shows how to use custom data structures in your room's state.
commands
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
left
right


The NRL stars moving to Super League for the 2020 season
by Marc BazeleyThe 12 Super League teams are already back in pre-season training as preparations for the 2020 campaign get underway, with plenty of off-season signings getting used to their new surroundings.
As ever, several clubs have cast their net further afield to the NRL, bringing in some big names, unheralded gems and familiar faces they hope will boost their prospects for next season.
Here, we take a look at those who are making the switch from Down Under and what they could bring to Super League next year…
James Maloney (Catalans Dragons)
Signed from: Penrith Panthers.
Position: Half-back.
Honours: 2x NRL Grand Final (2013, 2016), 2x State of Origin (2018, 2019), 1x Four Nations (2016), 3 Australia caps.
The 33-year-old makes the switch to Super League for 2020 after a decade-long NRL career for Melbourne Storm, New Zealand Warriors, Sydney Roosters, Cronulla Sharks and Penrith. Maloney has been a prolific point-scorer throughout his career and could well light up the competition with the French side in the same way New Zealand star Stacey Jones did.
Aidan Sezer (Huddersfield Giants)
Signed from: Canberra Raiders.
Position: Half-back.
Honours: 1 Turkey cap.
Sezer was one of the driving forces as Canberra reached their first NRL Grand Final for a quarter of a century in 2019 and has joined the Giants as a marquee player. The 28-year-old, who made his professional debut for Gold Coast Titans and joined the Raiders in 2016, is highly-regarded as an on-field leader and a nerveless goal-kicker.
Ligi Sao (Hull FC)
Signed from: New Zealand Warriors.
Position: Prop/second row.
Honours: 1 cap for Samoa.
Linking up with former Warriors team-mate Tevita Satae, who joined Hull in August, Sao will add some more steel and versatility to the Hull pack. The 27-year-old's hard-charging style is matched by his slick handling and offloading ability, so he should provide plenty of go-forward on the attacking side as well.
Mahe Fonua (Hull FC)
Signed from: Wests Tigers
Position: Wing/centre
Honours: 1x World Club Challenge (2013), 2x Challenge Cup (2016, 2017), 2x Super League Dream Team (2016, 2017), 6 Tonga caps.
It is a welcome return to the KCOM Stadium for the three-quarter, who acquired cult hero status during his first spell with Hull and was an integral part of their 2016 and 2017 Challenge Cup triumphs. The past two years at the Tigers have been disrupted by injury, so Hull fans will hope Fonua is over those issues and can replicate his previous displays for the club.
Manu Ma'u (Hull FC)
Signed from: Parramatta Eels.
Position: Second row.
Honours: 10 Tonga caps, 6 New Zealand caps.
His nickname of the 'Tongan Terminator' reveals much about Ma'u's style of play, with his tough tackling and hard running making him one of the most feared players in the NRL. But what should not be overlooked is his footwork and ability to spot a gap in the defensive line to help get his team on the front foot in attack.
Shaun Kenny-Dowall (Hull Kingston Rovers)
Signed from: Newcastle Knights.
Position: Wing/centre.
Honours: 1x NRL Grand Final (2013), 2x Four Nations (2010, 2014), 21 New Zealand caps.
It is not just the west side of Hull where NRL stars will be making their presence felt, with Rovers pulling off something of a coup to bring in one of this decade's stars of New Zealand rugby league. Capable of playing at either centre or one the wing, Kenny-Dowall will add a dangerous attacking dimension to Tony Smith's side.
Gareth Widdop (Warrington Wolves)
Signed from: St George Illawarra Dragons.
Position: Stand-off.
Honours: 1x NRL Grand Final (2012), 1x World Club Challenge (2013), 3 Great Britain caps, 28 England caps.
Widdop has been a regular in the England team since 2010, but next year will mark his first season playing in Super League as he grew up in Australia and came through the youth system at Melbourne Storm. A skilful stand-off who - as with others in the modern game - can slot in at full-back if needed, the Halifax-born player has goal-kicking skills in his armoury as well.
George Burgess (Wigan Warriors)
Signed from: South Sydney Rabbitohs.
Position: Prop.
Honours: 1x NRL Grand Final (2014), 1x World Club Challenge (2015), Dally M rookie of the year (2013), 15 England caps.
Another England regular who will be playing in Super League for the first time next season after coming through the South Sydney youth set-up. Like his twin brother Tom and recently-retired elder sibling Sam, George is a powerful, uncompromising forward and proven performer who will bring a huge presence to the Wigan pack.


WITNESS LIST Corrections Committee May 14, 1997-4:00P SB 250 For: Hamric, Rep. Peggy (Herself) Parish, Frank R. (Justice for All) Patterson, Sen. Jerry (Himself) Tier, Rob (C.C.I.) On: Dawson, Robert O. (U.T. Law School) Fabelo, Tony (CJPC) Klein, Susan R. (U.T. Law School) Reynolds, Carl (TBCJ) Registering, but not testifying: For: Bayley, Jeanne (Justice for All) Cotellesse, Suzan (Herself) Donahue, Sterlene (Justice for All) Gaither, E.H. (Justice for All) Hubbarth, William R. (Justice for All) Klages, George J. (Justice for All) Lemmon, Richard (Justice for All) Lowery, Mark (Himself) Lyons, Laura (T.A.A.S.A.) Mancuso, Patricia (Justice for All) Mulcahy, Vicki (Justice for All) Nicolaou, Joanna S. (Herself) Palmer, Stephanie (Justice for All) Parish, Shirley (Justice for All) Schambon, Audrey (Justice for All) Schambon, C.W. (Justice for All) Semander, Harriet (Justice for All) Semander, Zahari J. (Himself) Teer, Patsy M. (Justice for All) Against: Burnley, Rita Anne (Herself)


Articles
API
Logout
Article Editor
Use asset tags as placeholders inside article body to display images
Assets
Content
[[${body}]]


I consider myself a fairly experienced psychonaut, having had my share of psychedelics, pharmaceuticals, plants etc. One day I found a bag of Acorus calamus root powder which I had purchased from an online vendor during my university years (about 5 years ago). The bag originally contained 50mg of very fine powder but now seemed to contain somewhere between 30 and 35g. I can't remember when or how I had used the powder that was missing, but I had probably mixed it with other stuff, otherwise I would remember. The bag had remained sealed in a dry, dark place. The powder had formed hard rocks but looked otherwise unchanged.
I first crumbled the rocks to powder again, by applying pressure on the plastic bag. I took a 350ml bottle of vodka, emptied about 50ml to make space, and used a funnel to pour the powder into the bottle. I closed the lid and shook vigorously. I left the bottle stand for a couple of hours, shaking every once in a while. In retrospect, I could have waited longer for better results. Then, I took another, empty bottle. I put the funnel into the neck of the empty bottle, and a coffee filter inside the funnel. Then I started pouring the vodka and the calamus sludge into the filter, and watched as the honey-colored vodka started dripping into the empty bottle. I left the vodka filter throughout the night, although I suspect it didn't need that long. What I got was a bottle of honey-colored vodka.
At the time of the experiment, I was at my home, alone, with no immediate responsibilities and in good psychological state. I had been smoking pot since morning and by the time I started it was 6 in the afternoon. I had half a pizza a few hours earlier so I'm not hungry, I'm not feeling too full either.
18:08 T+0:00 I poured about a quarter of the extract into a glass and had a small sip to taste it. The liquid had a mild warm/spicy taste that was not too unpleasant, but I mixed the vodka with orange juice so that the alcohol would go down easier.
T+0:01 I had a much larger sip, this time the orange juice masked the taste of the alcohol but not the calamus. Again, this was not an unpleasant taste, it is however strong and very distinctive. I can see how some people could find it unpleasant, but I'd say that it goes down fairly easily.
T+0:06 I am now half way through my glass and now the taste seems rather unpleasant. I feel a very slight irritation in the stomach, which could be attributed to the alcohol.
T+0:13 I finished my glass, by now the taste seemed very bitter and unpleasant. I am feeling mildly drunk from the alcohol, but I hope the main effects will wear off before the TMA-2 kicks in.
[Erowid Note: The idea that a chemical in calamus metabolizes to TMA-2 in the body is pure speculation.] I drank a large glass of water too, to prepare for any dehydration that might arise from mixing an amphetamine with alcohol. My experience is that when using psychoactives, one must be careful to stay properly hydrated.  I am not planning to drink any more tonight. If my rough estimates are correct (I really should buy a scale to use in my experiments), I have ingested the extract of about 7 to 9 grams of root powder, which I think is more than enough for a first try. And now, to play the waiting game...
T+0:26 I am feeling a buzz that I think is different from the drunkenness I am experiencing. The spicy taste that still lingers in my mouth, and the warm, fuzzy feeling both remind me of my nutmeg experiments, and this is something that takes my mind years back to my university days, when I must have purchased the root powder.
T+0:50 I am definitely feeling a distinct buzz. I am chatting online with a good friend, and I'm telling her about what I'm doing. My typing skill has not been impared.
T+0:58 I notice that my hands are a bit sweaty, and the buzz continues. Nothing special.
T+1:04 Now I'm not just feeling a buzz, but a happy sensation, also I'm slightly sleepy in an amphetamine-kind of way. I don't really want to go to sleep, I guess the word I'm looking for is drowsy. I am also feeling a pleasant pressure around my head.
T+1:16 I discover that I feel happy and content when I let my eyes slightly lose focus. This is something I have also experienced with drugs from the amphetamine family. I don't like the side-effects of the amphetamines (and that's why I gave up ecstasy/speed/etc a long time ago), but today I am experiencing none of the unpleasant side-effects.
T+1:23 I decide to spoil the experiment a bit and light up a J. It intensified the effects slightly.
T+1:50 Still feeling buzzed. Pleasant but nothing spectacular. I'm not feeling any of the nausea that is often reported either. Nor do I feel any other unpleasant symptoms. I'm beginning to think that the plant material might have degraded due to me storing it for such a long time.
T+2:24 Effects are subsiding.
T+2:41 Now I'm close to baseline.
Overall it was a pleasant experience, definitely not a placebo, and I plan to repeat it in a few days, maybe stepping up the dosage, since I still have three times as much liquid left as I drank today. But once I run out, I don't think I'll be in any rush to acquire more calamus. For me it was a mild experience but if you are planning to follow my steps keep in mind that the material I used might have lost some potency because I kept it stored for so long. Use caution and common sense and always be safe. Peace.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


The philosophical study of any special science must center on the structures and categories appearing in its explanations. In its explanations of the reactivity and spectroscopic behavior of chemical species, modern chemistry is closely associated with the appeal to atomic and molecular structures. The roots of this explanatory tradition lie in the nineteenth century, which saw the emergence of the periodic table as well as an array of hypothetical molecular structures put to use in explaining chemical combination. In the twentieth century, this heritage was consolidated in two ways. Firstly, chemical structure theory was elaborated into a vast body of dynamical reaction mechanisms and a distinct tradition of visual representation and explanation. Secondly, the emergence of the interdisciplinary fields of chemical physics and quantum chemistry brought deeper physical insight to chemical explanations. Put together, these nineteenth and twentieth century developments raise a number of issues worthy of philosophical attention.
The first group of issues concerns the depth and quality of explanations provided by the early twentieth century unifications of chemical and physical theory. To assess these explanations, understanding late nineteenth century chemistry is very important. Many nineteenth century chemists were skeptical about the explanatory status of atoms and molecules. It is usually assumed that these doubts were assuaged (except on the part of some stubborn individuals) by microstructural explanations of optical isomerism and the law of constant proportions. However, there were genuine reasons to doubt the quality of these and related explanations well into the twentieth century. This is especially interesting given the frequency with which philosophers cite nineteenth-century atomism as a canonical example of inference to the best explanation.
One explanatory difficulty toward the close of the nineteenth century was the presence of significant gaps and vagueness in the mechanisms invoked by atomic explanations. For example, explanations of optical isomerism could account only for the number of different isomers of a given empirical formula, a fact that could also be accounted for by several other hypotheses. The details of how plane-polarized light could be rotated by interaction with chiral molecules came only much later. Similarly, early molecular explanations of the stoichiometry of chemical reactions were devoid of mechanistic detail. At the same time, opponents of atomism like Pierre Duhem could point to independent energetic explanations of chemical change, explanations that posited no explanatorily idle wheels. Thus, we believe that understanding exactly what the explanatory successes of atomism were and when they were actually achieved is critical to developing a sophisticated understanding of scientific explanation.
The second group of issues concerns the distinct tradition of explaining and representing chemical change. Historians of science have documented the development of this tradition in the nineteenth century, and the twentieth-century emergence of the interdisciplinary field of quantum chemistry. The persistence of chemical explanation in this new interdisciplinary field brought intense methodological debate. Chemical advocates of quantum-mechanical explanations of chemical bonding, like Linus Pauling and C.A. Coulson, sought to persuade their skeptical chemical colleagues of the value of quantum-mechanical models by tailoring these models to recover core explanatory features of qualitative molecular theories. In contrast, prominent physicists like Max Born emphasized the requirement that molecular quantum mechanics should preserve theoretical rigor, even at the expense of radical revisions to central chemical notions like valence and structure. Critics of this revisionism worried about loss of explanatory power, while the revisionists worried that the chemistryfriendly “models” of chemical bonding were ad hoc and simplistic. It is easy to think of philosophical accounts of explanation that would favor Born’s rigorous theoretical derivations on the one hand, or Pauling’s intuitive models on the other. But can their disagreement be recovered as the legitimate consequence of their differing disciplinary commitments?
Developments in computer modeling in the last thirty years have rendered molecular models dynamic, predictive, and visually striking. New developments have also sharpened the earlier disciplinary divide between theorists who work on “qualitative theory’’ and those working on “quantitative theory.” The distinction between one tradition of modeling (qualitative) that tries to be explanatory and another (quantitative) that simply tries to be as accurate and precise as possible poses important challenges to extant philosophical theories of explanation. One challenge concerns the issue of truth. If explanantia are taken to be more explanatory the closer they come to truth, how could highly idealized “qualitative” models be more explanatory than highly accurate quantitative ones?
Another issue raised by the development of quantum chemistry concerns the role of causal concepts in chemistry. Throughout the twentieth century, philosophers of science have suggested various ways to and motivations for excising causal talk from science. Prima facie, quantum chemistry seems to provide a new way to complete this project. Traditional chemical talk about “hydrolyzing,” “bond breaking,” and “oxidizing,” might be replaced with elegant mathematical models that are manipulated on powerful computers. Is there some important role that causal talk plays in chemistry that even the most elegant quantum mechanical model cannot replace?
We believe these topics represent some of the central, but underexplored, areas of philosophy of chemistry. Understanding these topics will also help to deepen our general accounts of explanation, causation, approximation and scientific realism.
Philosophers frequently cite Dalton's chemical atomism, and its 19th century
developments, as a prime example of inference to the best explanation.
This was a controversial issue in its time. But the critics are dismissed
as positivist-inspired antirealists with no interest in explanation. Is
this a reasonable assessment?
Historians of science have documented the different backgrounds and assumptions brought to early quantum chemistry by physicists and chemists. In this paper I investigate their differing views of theoretical explanation, through methodological comments from John Clarke Slater, Linus Pauling and Charles Coulson. Slater tended to argue for quantum-mechanical rigour, and the application of fundamental principles in models of molecular bonding. Although on different sides of the debate between the valence-bond and molecular-orbital approaches, Pauling and Coulson both emphasised continuity with existing chemical explanations, and systematic explanatory power within chemistry.
I consider two ways the concept of causation could be excised from chemical practice, one suggested by Russell's claim that a mature science should dispense with causation in favor of mathematical regularities, the other by Kitcher's view that causes are just a subset of unifying patterns which play a particular psychological role for us. Both of these ways of removing causation would create significant changes in chemistry. Russellian chemistry might improve chemists’ projects of prediction, at least locally, but it would be at odds with their explanatory projects and would leave the descriptive projects involving new measurement techniques largely unmotivated. On the other hand, Kitcherian chemistry is at first blush well equipped to handle explanatory tasks. However, it would force chemists to accept certain unifying patterns as explanatory, which they do not think are at all explanatory. This might head off some descriptive lines of enquiry and damage prospects for the identification of potentially larger-scale explanations. More important than this, to chemists, it could put them off from finding the explanatory patterns that are true — true because they get at the real structure of the chemical phenomena in the world.
Modern theoretical practice in chemistry can be roughly divided into two categories. The first is often called “quantitative theory.” This practice involves building purely quantum mechanical models and using sophisticated numerical analysis techniques to make extremely accurate predictions about molecular properties. The other theoretical practice is called “qualitative theory.” Qualitative theorists build models that are supposed to deepen our understanding of chemical phenomena. These models are often highly idealized or otherwise inaccurate from the point of view of purely quantum mechanical models. Some chemists have claimed that the simple models of qualitative theory are more explanatory than quantitative models, although they are obviously not the best at making predictions. If this is true, it poses a problem for extant accounts of scientific explanation, especially ones that make either truth or nomic expectability a criterion for explanantia being explanatory. In this paper, I give a general framework for understanding qualitative theory and argue why it is (at least sometimes) more explanatory than quantitative theory. I will also discuss what kind of theory of explanation we will need to adopt in order to capture this interesting aspect of modern chemical theoretical practice.


Recipe 20.1. Getting Fresh Default Values at Each Function Call
Credit: Sean Ross
Problem
Python computes the default values for a function's
optional arguments just once, when the function's
def statement executes. However, for some of your
functions, you'd like to ensure that the default
values are fresh ones (i.e., new and independent
copies) each time a function gets called.
Solution
A Python 2.4 decorator offers an elegant solution, and, with a
slightly less terse syntax, it's a solution you can
apply in version 2.3 too:
import copy
def freshdefaults(f):
"a decorator to wrap f and keep its default values fresh between calls"
fdefaults = f.func_defaults
def refresher(*args, **kwds):
f.func_defaults = deepcopy(fdefaults)
return f(*args, **kwds)
# in 2.4, only: refresher._ _name_ _ = f._ _name_ _
return refresher
# usage as a decorator, in python 2.4:
@freshdefaults
def packitem(item, pkg=[ ]):
pkg.append(item)
return pkg
# usage in python 2.3: after the function definition, explicitly assign:
# f = freshdefaults(f)
Discussion
A function's default values are evaluated once, and
only once, at the time the function is defined (i.e., when the
def statement executes). Beginning Python
programmers are sometimes surprised by this fact; they try to use
mutable default values and yet expect that the values will somehow be
regenerated afresh each time they're needed.
Recommended Python practice is to not use mutable default values.
Instead, you should use idioms such as:
def packitem(item, pkg=None):
if pkg is None:
pkg = [ ]
pkg.append(item)
return pkg
The freshdefaults decorator presented in this recipe
provides another way to accomplish the same task. It eliminates the
need to set as your default value anything but the value you intend
that optional argument to have by default. In particular, you
don't have to use None as the
default value, rather than (say) square brackets [
], as you do in the recommended idiom.
freshdefaults also removes the need to test each
argument against the stand-in value (e.g., None)
before assigning the intended value: this could be an important
simplification in your code, where your functions need to have
several optional arguments with mutable default values, as long as
all of those default values can be deep-copied.
On the other hand, the implementation of
freshdefaults needs several reasonably advanced
concepts: decorators, closures, function attributes, and deep
copying. All in all, this implementation is no doubt more difficult
to explain to beginning Python programmers than the recommended
idiom. Therefore, this recipe cannot really be recommended to
beginners. However, advanced Pythonistas may find it useful.
|
If an outer function just returns an inner function (often a
closure), the name of the returned function object is fixed, which
can be confusing when the name is shown during introspection or
debugging:
>>> def make_adder(addend):
... def adder(augend): return augend+addend
... return adder
...
>>> plus100 = make_adder(100)
>>> plus_23 = make_adder(23)
>>> print plus100(1000), plus_23(1000)
1100 1023
>>> print plus100, plus_23
<function adder at 0x386530> <function adder at 0x3825f0>
As you see, the functionality of plus100 and
plus_23 is correct (they add 100 and 23 to their
argument, respectively). Confusingly, however, their names are both
'adder', even though they are different functions.
In Python 2.4, you can solve the problem by setting the _
_name_ _ attribute of the inner function right after the
end of the inner function's def
statement, and before the return statement from
the outer function:
def make_adder(addend):
def adder(augend):
return augend+addend
adder._ _name_ _ = 'add_%s' % (addend,)
return adder
With this change in make_adder, the previous snippet
would now produce more useful output:
>>> print plus100, plus_23
<function add_100 at 0x386530> <function add_23 at 0x3825f0>
Unfortunately, in Python 2.3, you cannot assign to the _
_name_ _ attribute of a function object; in that release,
the attribute is read-only. If you want to obtain the same effect in
Python 2.3, you must follow a more roundabout route, making and
returning a new function object that differs from the other only in
name:
import new
def make_adder(addend):
def adder(augend): return augend+addend
return new.function(adder.func_code, adder.func_globals, 'add_%s' % (addend,),
adder.func_defaults, adder.func_closure)
|
See Also
Python Language Reference documentation about
decorators; Python Language
Reference and Python in a Nutshell
documentation about closures and function attributes;
Python Library Reference
and Python in a Nutshell documentation about
standard library module copy, specifically
function deepcopy.
|


A floating quantity in a non-specific fixed unit.
A real number in particular units. Quantity sub-classes override units and __str__.
Return the number spelt out as words (e.g. eleven or one hundred twenty three).
Mixin class to extend the Format Specification mini-language.
Return a nice representation when dividing by a Quantity (overridden in Fractional_Quantity).
See Fractional_Quantity for a nice fractional representation.
Format :b format displays it as blank when zero. e.g. 0.00:b -> .
Format :i format displays it in integer format, if possible. e.g. 5.00%:i -> 5%.
Format a PayRate Rate, shortening $1,000’s to $k’s, e.g. $50,000pa -> $50k.
Support a /rate format specification, i.e. {value:spec/rate}.
Drop the new format specs. They are only only processed when called explicitly from a Qty sub-class.
Split the new format specifier id out from the format spec.
A Fractional Quantity displays as a Fraction (e.g. 52/12).
This is useful, for example, when converting months to weeks.
Return a nice representation when dividing by a Fraction, e.g. /(52/12) -> *12/52.
Fractions can be displayed with a preferred_demonimator, for convenience. This is instead of the standard python limit_denominator which uses the lowest possible denominator. e.g. 52 weeks / 12 months can be displayed as 52/12 rather than 13/3.
A percentage. Transparently handles a divisor of 100. (e.g. Percent(5) is displayed as 5% and stored as 0.05).
Qty is a base class for objects with a value represented by some Units.
Describe a conversion, e.g. {num:>10/hr}.format(10*dollars) -> $10.00/hr.
Return the formatted Units part only.
Return the formatted Quantity (value part only).
The name of the units.
Unit is a base class that represents a unit for a Quantity.
Return the unit name formatted as a String. (Note: This handles plural forms).
Usage: e.g. rate = 5 * percent
Usage: e.g. pieces = 40*qty


GOING ALL THE WAY
A Film Review by James Berardinelli
RATING (0 TO 10): 7.0 Alternative Scale: *** out of ****
United States, 1997 U.S. Release Date: 10/3/97 (limited) Running Length: 1:43 MPAA Classification: R (Sexual situations, nudity, profanity, violence) Theatrical Aspect Ratio: 1.85:1
Cast: Jeremy Davies, Ben Affleck, Amy Locane, Rachel Weisz, Rose McGowan, Jill Clayburgh, Lesley Ann Warren Director: Mark Pellington Producers: Tom Gorai, Sigurjon Sighvatsson Screenplay: Dan Wakefield based on his novel Cinematography: Bobby Bukowski Music: tomandandy U.S. Distributor: Gramercy Pictures
GOING ALL THE WAY, based on Dan Wakefield's 1970 bestselling novel of the same name, is a coming of age story with characters who are a little older than is the norm for this genre. While most stories about the rituals of entering adulthood are set in high schools, GOING ALL THE WAY looks at two twentysomething men who, having served during the Korean War, are fresh out of the army and trying to find their place in the world. And, since the movie is set in 1954, it addresses the roles of religion and sex in the rites of passage -- this is, after all, an era when the latter was taboo and the former was de rigueur.
Sonny (Jeremy Davies) and Gunner (Ben Affleck) are an unusual pair of close friends. Although both attended the same high school and each joined the army after graduation, that's where the similarity ends. Sonny is a shy, alienated young man who comes from a deeply conservative family and who gets tongue-tied around pretty girls. His war experience was limited to guarding the home front from Kansas City. Gunner, on the other hand, is an ex-jock who spent time in Korea and Japan. He's popular, well-liked, and can get any girl he wants.  Yet, one day while talking, Sonny and Gunner realize that, despite the differences in their personalities and backgrounds, they have very similar concerns and questions about life, love, and the future. The two become inseparable, but, although their friendship is real, it is not a match of equals. The brash and confident Gunner is the leader and Sonny is always the follower.
Women are, of course, the unsolved (and perhaps unsolvable) mystery. Gunner falls for a sexy art student named Marty (Rachel Weisz, sporting an unbelievably irritating faux American accent), while Sonny is looking for a way out of a dead-end relationship with his high school sweetheart, the loyal-but-uninteresting Buddy (Amy Locane). He finds his escape in Gale (Rose McGowan), but learns the hard way that dream girls are sometimes better left in dreams.
Kurt Vonnegut once described Dan Wakefield's novel, GOING ALL THE WAY, as "the Midwestern CATCHER IN THE RYE," and, while the film doesn't have quite the depth one might expect from a story tagged with that appellation, it's easy to see why Vonnegut made the comparison. GOING ALL THE WAY deals believably with the tribulations of new adulthood and the youthful need to break free in a world that seeks to repress. Many male viewers, regardless of the era they grew up in, will see bits and pieces of themselves in Sonny and Gunner.
The movie, adapted by Wakefield and directed by MTV alum and first time feature filmmaker Mark Pellington, is at times uneven. GOING ALL THE WAY contains elements of comedy ranging from subtle humor to blatant satire (most of the latter involve a scathing view of religion and conservatism in the '50s). Not all of these blend seamlessly with the movie's more dramatic elements, and several of the comic-to-serious transitions are jarring (such as the tragedy that follows closely upon Sonny's surreal trip into a fundamentalist church where he asks directions to a whore house).
The women in the film function mostly as plot devices and attractive decorations. None of them have any personality or depth. Jill Clayburgh and Lesley Ann Warren , as Sonny and Gunner's mothers, respectively, are stereotypes. They are used to provide humor and emphasize the differences and, perhaps surprisingly, the similarities between religious conservatism and progressive liberalism.
Fortunately, the two leads are well-developed and ably portrayed. Ben Affleck (CHASING AMY) has the blend of charm and bravado necessary to bring Gunner to life. His co-star, Jeremy Davies (who can also be seen in THE LOCUSTS), plays a character not unlike the one he essayed in SPANKING THE MONKEY. Davies has an aptitude for fleshing out insecure individuals who have been dealt a raw hand by fate, and, as a result, are forever trapped. The rapport established between Affleck and Davies is effective -- it's not difficult to accept that these two mismatched young men have become fast friends.
Because of the nature of the material, GOING ALL THE WAY will probably appeal more to males than females, although, as with any well- constructed motion picture, there's nothing to prevent a woman from enjoying it. However, while the novel may have been an important and influential work of literature, the motion picture adaptation doesn't ascend to the same lofty heights. GOING ALL THE WAY is a pleasant way to spend one-hundred minutes, and the characters are fashioned with enough detail for us to care about them, but this is in no way a seminal or transforming movie. The only thing that sets it apart from so many forgettable period piece coming-of-age stories is that it has been put together with a degree of care and skill.
Copyright 1997 James Berardinelli
- James Berardinelli e-mail<EMAIL_ADDRESS>The website has moved!! The new address is: http://movie-reviews.colossus.net/
"The cinema is not an art which films life: the cinema is something between art and life. Unlike painting and literature, the cinema both gives to life and takes from it..."
- Jean-Luc Godard
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


Microsoft PowerPoint comes with different views to help you while you are creating a presentation. The two main views you use in PowerPoint are normal view and slide sorter view. To easily switch between views, you click the buttons at the lower left of the PowerPoint window.
You can see the small icons of normal view ,outline view ,slide view,slide sorter view ,slide show.
Normal viewNormal view contains three panes --> the outline pane, the slide pane, and the notes pane. These panes let you work on all aspects of your presentation in one place. You can adjust the size of the different panes by dragging the pane borders.
Outline pane Use the outline pane to organize and develop the content of your presentation. You can type all of the text of your presentation and rearrange bullet points, paragraphs, and slides.
Slide pane: In the slide pane, you can see how your text looks on each slide. You can add graphics, movies, and sounds, create hyperlinks, and add animations to individual slides.
Notes pane: The notes pane lets you add your speaker notes or information you want to share with the audience. If you want to have graphics in your notes, you must add the notes in notes page view.
These three panes are also displayed when you save your presentation as a Web page. The only difference is that the outline pane displays a table of contents so that you can navigate through your presentation.
Slide sorter view :In slide sorter view, you see all the slides in your presentation on screen at the same time, displayed in miniature. This makes it easy to add, delete, and move slides, add timings, and select animated transitions for moving from slide to slide.
Slide Show :You can also preview animations on multiple slides by selecting the slides you want to preview and then clicking Animation Preview on the Slide Show menu.At any time while you are creating your presentation, you can start your slide show and preview your presentation by clicking Slide Show .


Suppose we start with n dollars, and make a sequence of bets. For each bet, we win 1 dollar with probability p, and lose 1 dollar with probability 1 − p. We quit if either we go broke, in which case we lose, or when we reach T = n + m dollars, that is, when we win m dollars. For example, in Roulette, p = 18/38 = 9/19 ∼ 0.473. If n = 100 dollars, and m = 100 dollars, then T = 200 dollars. What are the odds we win 100 dollars before losing 100 dollars? Most folks would think that since 0.473 ∼ 0.5, the odds are not so bad. In fact, as we will see, we win before we lose with probability at most 1/37649!
This random walk is a special type of random walk where moves are independent of the past. If p = 1/2, the random walk is unbiased and is called a .For p ≠ 1/2, the random walk is biased (). If the walk hits a boundary (0 or n + m), then we stop playing.
Let’s figure out the probability that we gain m before losing n. To set things up formally, let W be the event we hit T before we hit 0, where T = n + m. Let Dt be a random variable that denotes the number of dollars we have at time step t. Let Pn = ℙ(W|D0 = n) be the probability we get T before we go broke, given that we start with n dollars. Our question then, is what is Pn ? We’re going to use a recursive approach. Pn = p ⋅ Pn + 1 + (1 − p) ⋅ Pn − 1, for 0 < n < T
Solving it for p < 0.5 yields
This last expression is even independent of n, and exponentially small in m.
Why does this seem to run against our intuition ? Normally we would think that the probability of winning 100 dollars before losing 200 dollars is better than winning 10 before losing 10, i.e., that the ratio is what matters. In fact, the ratio is what matters if the game is fair, i.e., if p = 1/2. In that case, we simply have Pn = n/(n + m) = n/T In this case, if n = 200 and m = 100, we have Pr(Win)=200/300=2/3. On the other hand, if n = 10 and m = 10, then Pr(Win)=10/20=1/2. Thus, actually, now we are more likely to win in the first case!
So the trouble is that our intuition tells us that if the game is almost fair, then we expect the results to be almost the same as if the game were fair. It turns out this is not the case!


STORE-MANAGER-APP
All Products
my profile
Logout
Top selling Products
phones@kes 200
webcams@kes 300
wrist watch@290


Identify a helper and review the emergency plan with the mother
Prepare the birth companion or another skilled helper to assist if the baby does not breathe.
- A birth companion can help the mother and call for another helper
- A second skilled helper can assist in caring for the baby
Prepare the area for delivery
The area where a baby is born should be
| Warm | Close windows and doors to stop drafts. Supply heat as needed. |
| Well-lighted | Use a portable lamp if needed to assess the baby. |
| Clean | Help mother wash her hands and prepare a clean cloth to cover the baby during skin- to-skin care. |
Wash hands
Handwashing helps prevent the spread of infection. Wash hands with soap and clean water or use an alcohol-based cleaner before and after caring for a mother or a baby (see page 52). Be sure that everyone at the birth washes their hands. Gloves also protect from infections carried by blood and body fluids.
Prepare anarea for ventilation
Prepare a warm, dry, flat, and safe space for the baby to receive ventilation if needed. Prepare a safe delivery kit, uterotonic (such as oxytocin or misoprostol), and equipment to help a baby breathe. Equipment should be disinfected after use and kept clean. Check that all equipment and supplies are ready for use in the area for ventilation. Test the function of the ventilation bag, mask, and suction device (see page 47).
Practice key skills
Practice in pairs
Practice the four steps to prepare for a birth


|
Package body pit_console_pkg Implementation of PIT_CONSOLE output module |
| Program units |
| initialize | Initialization |
| Helper to print a message to the console | |
| print_call_stack | Helper to print the content of a call stack |
| log | |
| log | |
| enter | |
| leave | |
| context_changed | |
| initialize_module |
| Variables |
| g_message_template | |
| g_enter_template | |
| g_leave_template | |
| g_level_indicator |
| Constants |
| C_PARAM_GROUP | |
| C_PIT_CONSOLE | |
| C_FIRE_THRESHOLD | |
| C_ENTER_TEMPLATE | |
| C_LEAVE_TEMPLATE | |
| C_MESSAGE_TEMPLATE | |
| C_LEVEL_INDICATOR |
C_PARAM_GROUP
C_PARAM_GROUP constant varchar2(20 char) := 'PIT';
C_PIT_CONSOLE
C_PIT_CONSOLE constant varchar2(20) := 'PIT_CONSOLE';
C_FIRE_THRESHOLD
C_FIRE_THRESHOLD constant varchar2(30 char) := C_PIT_CONSOLE || '_FIRE_THRESHOLD';
C_ENTER_TEMPLATE
C_ENTER_TEMPLATE constant varchar2(30 char) := C_PIT_CONSOLE || '_ENTER_TEMPLATE';
C_LEAVE_TEMPLATE
C_LEAVE_TEMPLATE constant varchar2(30 char) := C_PIT_CONSOLE || '_LEAVE_TEMPLATE';
C_MESSAGE_TEMPLATE
C_MESSAGE_TEMPLATE constant varchar2(30 char) := C_PIT_CONSOLE || '_MSG_TEMPLATE';
C_LEVEL_INDICATOR
C_LEVEL_INDICATOR constant varchar2(30 char) := C_PIT_CONSOLE || '_LEVEL_INDICATOR';
g_message_template
g_message_template varchar2(2000);
g_enter_template
g_enter_template varchar2(2000);
g_leave_template
g_leave_template varchar2(2000);
g_level_indicator
g_level_indicator varchar2(10);
initialize
Procedure initialize
Initialization
| Usage |
|
Reads several parameters into global variables |
Procedure print(p_message in clob)
Helper to print a message to the console
| Usage |
|
Called to print a message text to the console, reducing output to 32KByte to take limitations of DBMS_OUTPUT into account |
| Parameters |
| p_message |
Message to print to the console |
print_call_stack
Procedure print_call_stack(p_call_stack in call_stack_type, p_template in varchar2)
Helper to print the content of a call stack
| Usage |
|
Templates are defined as parameters and referenced here to control the formatting of the call stack. After formatting, procedure PRINT is called to print the call stack. |
| Parameters |
| p_call_stack | Instance of call stack to print | |
| p_template |
Name of the template to be used to format the output. |
log
Procedure log(p_message in message_type)
log
Procedure log(p_log_state in log_state_type)
enter
Procedure enter(p_call_stack in call_stack_type)
leave
Procedure leave(p_call_stack in call_stack_type)
context_changed
Procedure context_changed(p_ctx in pit_context)
initialize_module
Procedure initialize_module(self in out pit_console)


Before Change
if self.max_sequence_length and max_length_x > self.max_sequence_length:
max_length_x = self.max_sequence_length
// truncation of sequence at max_sequence_length
x_tokenized = truncate_batch_values(x_tokenized, self.max_sequence_length)
// prevent sequence of length 1 alone in a batch (this causes an error in tf)
extend = False
if max_length_x == 1:
max_length_x += 1
extend = True
// generate data
if self.embeddings.use_ELMo:
batch_x = to_vector_simple_with_elmo(x_tokenized, self.embeddings, max_length_x, extend=extend)
elif self.embeddings.use_BERT:
batch_x = to_vector_simple_with_bert(x_tokenized, self.embeddings, max_length_x, extend=extend)
else:
batch_x = np.zeros((max_iter, max_length_x, self.embeddings.embed_size), dtype="float32")
// store sample embeddings
for i in range(0, max_iter):
batch_x[i] = to_vector_single(x_tokenized[i], self.embeddings, max_length_x)
if self.preprocessor.return_casing:
batch_a = np.zeros((max_iter, max_length_x), dtype="float32")
After Change
if self.max_sequence_length and max_length_x > self.max_sequence_length:
max_length_x = self.max_sequence_length
// truncation of sequence at max_sequence_length
x_tokenized = np.asarray(truncate_batch_values(x_tokenized, self.max_sequence_length))
// prevent sequence of length 1 alone in a batch (this causes an error in tf)
extend = False
if max_length_x == 1:
max_length_x += 1
extend = True
// generate data
if self.embeddings.use_ELMo:
batch_x = to_vector_simple_with_elmo(x_tokenized, self.embeddings, max_length_x, extend=extend)
elif self.embeddings.use_BERT:
batch_x = to_vector_simple_with_bert(x_tokenized, self.embeddings, max_length_x, extend=extend)
else:
batch_x = np.zeros((max_iter, max_length_x, self.embeddings.embed_size), dtype="float32")
// store sample embeddings
for i in range(0, max_iter):
batch_x[i] = to_vector_single(x_tokenized[i], self.embeddings, max_length_x)
if self.preprocessor.return_casing:
batch_a = np.zeros((max_iter, max_length_x), dtype="float32")


Loading files... please wait
Cannot able to fetch file list for this challenge. Try again
{{deleteError | json}}


Low standards in schools across the East Midlands region of England are exposing the educational fault line dividing the nation, Ofsted’s Chief Inspector said today.
Sir Michael Wilshaw highlighted figures showing the East Midlands as the worst performing region in the country on a range of key indicators.
He blamed a culture of complacency and a lack of clear accountability for the poor educational performance of towns and cities across the region and across all phases.
Sir Michael made his comments on the same day that Ofsted’s Regional Director for the East Midlands, Chris Russell, published
an open letter
to all those responsible for education in Northamptonshire. In the letter, he sets out his deep concerns about the low standards of achievement across the county.
Chris Russell said that far too many children and young people in Northamptonshire are being deprived of the opportunity to gain a good education, with weaknesses in the quality of provision persisting across every age group.
Sir Michael pointed out that these problems are not confined to this one local authority area, but are mirrored in a number of neighbouring towns and cities, and across the East Midlands region as a whole. For example:
-
the East Midlands is currently the joint lowest performing Ofsted region in terms of inspection outcomes, with almost one in three secondary schools judged less than good at their last inspection
-
the region had the worst GCSE results in England in 2015; nearly 46% of pupils did not achieve the benchmark five or more A* to C grades including English and maths
-
nearly 73% of East Midlands’ pupils eligible for free school meals (FSM) failed to achieve this benchmark
-
in the East Midlands children in care did worse than in any other region; just 10.2% of them achieved 5 or more A* to C grades in GCSE examinations, including English and maths.
Across the different phases of education, children in some of the region’s major urban areas and shire counties fare particularly badly:
-
Leicester is the poorest performing local authority in the country for pupil outcomes at the end of the Early Years Foundation Stage – with only 51% of the city’s children achieving a good level of development, compared with 66% nationally
-
Nottingham is England’s poorest performer in the phonics screening check at key stage 1 - just 69% of the city’s six and seven-year-olds met the required standard in 2015. In Derby, the figure was just 70%, compared with 77% of pupils nationally
-
Northamptonshire is one of the worst-performing local authority areas in the country for the achievement of disadvantaged children at key stage 2. Only 59% of FSM pupils in the county achieved the expected standards in reading, writing and mathematics at the end of primary school compared with 66% nationally. Their peers in Lincolnshire, Leicestershire and Derby fared nearly as badly, with just 60% achieving the expected standards
-
Derby and Nottingham were among the 10 lowest ranking local authority areas nationally for GSCE examinations – only 47.6% and 42.4% of pupils respectively achieved the benchmark five or more A* to C grades including English and maths in 2015
Sir Michael Wilshaw said:
These statistics should serve as a wake-up call. The poor quality of education in many parts of the East Midlands often passes under the radar as attention is focused on underperformance in the bigger cities of the North and West Midlands, like Manchester, Liverpool and Birmingham.
However, in many ways, the problems in this region symbolise more than anywhere else the growing educational divide between the South and the rest of England that I highlighted in my last Annual Report.
The Chief Inspector pointed out that there are very few high performing multi-academy trusts (MATs) in the region, while the support and challenge to schools from local authorities has not led to rapid enough improvement.
Sir Michael argued that there has been a collective failure by education and political leaders in the region to tackle mediocre provision and a culture of low expectations. While this is a particular problem among low income White British communities, the low level of GCSE attainment in places like Leicester – an area with a minority white British population – demonstrates that this extends beyond one ethnic group.
There are some bright spots across the region that are bucking these trends. Babington Community College, Leicester; Dronfield Henry Fanshawe and Chapel-en-le-Frith, both in Derbyshire are all outstanding secondary schools doing their best for their students. Meanwhile, outstanding primaries include Christ the King Primary School in Leicester City, Norbridge Primary in Worksop, Nottinghamshire and Carlton Road Academy in Boston, Lincolnshire. However, examples such as these are too scarce in the East Midlands.
Sir Michael said:
National politicians and policymakers must start to worry more about what is happening north of the Wash. They should be asking why schools in large parts of the East Midlands aren’t doing better.
Derby, the home of Rolls Royce, has a proud history of engineering excellence, but local secondary schools are failing to deliver top rate GCSE results.
Nottingham has three widely respected initial teacher education providers on its doorstep, but at primary level its phonics results are the worst in the country. At secondary level, its schools are amongst the poorest performers for GCSE examinations.
Leicester, meanwhile, has enjoyed great sporting success and is home to the new champions of English football. Yet when it comes to education, its ambitions and achievements are decidedly second division.
Our future prosperity as a nation depends on us delivering a better quality of education to all our children, wherever they live. As things stand, too many schools in the East Midlands are failing to equip young people with the knowledge and skills the country needs to keep pace with its international competitors.
As Chief Inspector, I am calling on local politicians across the region to do significantly more to challenge and support their local schools, regardless of whether they are academies or under local authority control.
Sir Michael’s view is echoed by Ofsted East Midlands Regional Director Chris Russell in his letter to the main education players in Northamptonshire.
Mr Russell says:
Across Northamptonshire there are too many early years providers and schools of all types and phases that are not good enough.
As a result, children do not achieve as well as they should. Disadvantaged children in the county are performing particularly poorly. There needs to be greater oversight and co-ordinated action from those accountable for educational provision in the county.
Note to editors
Read the
letter from Chris Russell
.
Yesterday, Chris Russell addressed the East Midlands Challenge conference in Nottingham, where he spoke about Ofsted’s views on what inspectors look for. Mr Russell also discussed priority learner groups and what good practice inspectors have seen around the region. This conference was aimed at Teaching School Alliances.


Client
Foursquare
Date
07/2018
Tools
After Effects
Illustrator
Sketch
three.js
Cinema4D
Role
A site highlighting Foursquare's pivot from just consumer facing apps, to a suite of enterprise-grade location intelligence tools and services.
Overview
Foursquare's B2B products focus on monetizing users' anonymized location data so that clients may derive relevant insights. The modern nature of these products makes them often difficult to explain and understand. Our challenge was to build a web property which would properly voice the new direction of the company, and deliver easily digestible explanations of our products.
Approach
Design an over arching experience that highlights Foursquare's departure from light hearted consumer facing to a trustworthy, future-facing B2B location intelligence partner. We acheived this by enlisting a darker color theme, adopting a more elegant style accross visuals, and creating engaging micro-ineteractions.
In order to ensure our offers were clear and succint, I created a visual style that would overlay our otherwise invisible technology over real world scenarios. By visually depicting how our location tech works, I was able to improve overall product understanding.
Explorations
Wireframe explorations allowed me to experiment with different interactions and methods of breaking down & delivering our offerings in the appropiate hiearchy, as well as determine possible interactive ways of teaching our products' core functionalities.
Product Pages
Each product page is opened with a straight to-the-point hero conveying the purpose of the product. It is then followed by key features, methodoloy and benefits. This gradual reveal of relevant information allows the user to quickly understand what the product is, how it works and if it will serve their particular need.
Micro Interactions
By thinking about the delivery of complex, jargon-filled product descriptions as more than just text, I was able to design and illustrate interactions that increase user engagement and in turn aids their understanding of what they're reading.
Re-thinking the menu
I wanted users to be able to have a basic grasp of of what they were clicking on before having to actually visit a separate page. This was acheived by foregoing the traditional list style menu for one that has a short description of each product.
Fast Follow
After deployment, I continued to support the project with various design solutions, such as an email sigh-up form which would also double in functionality as a notification overlay.


By default, the items displayed on the Timeline are unordered. They are stacked in the order that they where loaded. This means that way items are stacked can change while moving and zooming the Timeline.
To display and stack the items in a controlled order, you can provide a
custom sorting function via the configuration option order
.
WARNING: Custom ordering is only suitable for small amounts of items (up to a few hundred), as the Timeline has to render all items once on load to determine their width and height.


{% macro render_ec_line(test_id, base, info, result=None) %}
| The test has not been run | |
| Success | |
| Warning, something was not as expected | |
| Failed | |
| The test flow wasn't completed. This may have been expected or not | |
| Signals the fact that there are trace information available for the test |