I have some trouble with the base/RFM69Pi not processing all the frames sent by
my node (EmonTX V2).
It work correctly when I only
had a temperature sensor, but now since I upgraded it
with pulse counter not all frames seems to be
processed correctly.
A good frame:
2015-12-18 06:31:38,146 DEBUG RFM2Pi 81 NEW FRAME : OK 10 111 2 2 0 33 7 (-45)
2015-12-18 06:31:38,165 DEBUG RFM2Pi 81 Timestamp :<PHONE_NUMBER>.15
2015-12-18 06:31:38,178 DEBUG RFM2Pi 81 From Node : 10
2015-12-18 06:31:38,182 DEBUG RFM2Pi 81 Values : [623, 2, 18.25]
2015-12-18 06:31:38,185 DEBUG RFM2Pi 81 RSSI : -45
2015-12-18 06:31:38,201 INFO RFM2Pi Publishing: emonhub/rx/10/values 623,2,18.25
2015-12-18 06:31:38,216 DEBUG RFM2Pi 81 adding frame to buffer => [1450420298, 10, 623, 2, 18.25, -45]
Then I have loads of disregarded frames:
You can see from the first value and time stamp that these are not noise
2015-12-18 06:33:20,292 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 113 2 2 0 33 7 (-48)
2015-12-18 06:33:30,516 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 52 2 1 0 33 3 (-44)
2015-12-18 06:33:40,789 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 113 2 2 0 33 7 (-44)
Whilst noise looks like this:
2015-12-18 06:33:41,036 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 138 66 225 247 230 11 147 210 13 75 35 205 120 222 103 59 178 90 214 102 61 (-102)
The node config:
[[10]]
nodename = Sovrum
firmware = ""
hardware = "emonTX V2"
[[[rx]]]
names = W, p, T1
datacode = h
scales = 1,1,0.01
units = W,p,C
Previous config when only temperature was measured:
#[[10]]
# nodename = Sovrum
# firmware = ""
# hardware = "emonTX V2"
# [[[rx]]]
# name = T1
# datacode = h
# scale = 0.01
# unit = C
Any thoughts on this?
Thanks in advance!
Re: Emon not processing all frames from node
Oh, here is the node configuration:
[[10]]
nodename = Sovrum
firmware = ""
hardware = "emonTX V2"
[[[rx]]]
names = W, p, T1
datacode = h
scales = 1,1,0.01
units = W,p,C
Privous one when i only ran temperature (worked good):
#[[10]]
# nodename = Sovrum
# firmware = ""
# hardware = "emonTX V2"
# [[[rx]]]
# name = T1
# datacode = h
# scale = 0.01
# unit = C
Re: Emon not processing all frames from node
@Bjotksta,
The Discarding RX frame 'unreliable content' is because those packets are failing the CRC check, shown by the '?'.
If you could capture some more (with good packets in between), the bit position that is first failing will become clearer. The earliest part of the packet is ok since the node ID / length fields are correct - a glitch is occurring later on (seemingly quite early if that '52' is typical).
The signal strength is fine - this is more likely a timing issue. Your version of EmonTX V2 is using an RFM12B radio module?
Re: Emon not processing all frames from node
Thanks for the input!
Perhaps this is an error in the code of the emonTX, i should have a look at that.
The emonTX also has a RFM69 module.
Re: Emon not processing all frames from node
Got some more frames:
How do you decode the data?
2015-12-18 09:45:02,295 DEBUG RFM2Pi 666 NEW FRAME : OK 10 16 2 2 0 189 6 (-61)
2015-12-18 09:45:12,101 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 21 2 2 0 189 6 (-47)
2015-12-18 09:45:22,396 DEBUG RFM2Pi 667 NEW FRAME : OK 10 15 2 1 0 189 6 (-51)
2015-12-18 09:45:32,534 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 16 2 2 0 189 6 (-45)
2015-12-18 09:46:03,226 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 17 2 1 0 189 6 (-49)
2015-12-18 09:46:13,416 DEBUG RFM2Pi 670 NEW FRAME : OK 10 20 2 2 0 189 6 (-46)
2015-12-18 09:46:23,647 DEBUG RFM2Pi 671 NEW FRAME : OK 10 10 2 1 0 189 6 (-45)
2015-12-18 09:46:33,818 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 20 2 2 0 189 6 (-47)
2015-12-18 09:46:44,107 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 11 2 1 0 189 6 (-47)
2015-12-18 09:46:54,258 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 209 1 1 0 189 6 (-50)
2015-12-18 09:47:04,532 DEBUG RFM2Pi 672 NEW FRAME : OK 10 208 1 2 0 189 6 (-45)
2015-12-18 09:47:14,710 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 189 1 1 0 189 6 (-45)
2015-12-18 09:47:25,013 DEBUG RFM2Pi 673 NEW FRAME : OK 10 194 1 1 0 189 6 (-45)
2015-12-18 09:47:35,159 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 201 1 2 0 189 6 (-48)
2015-12-18 09:47:45,373 DEBUG RFM2Pi 674 NEW FRAME : OK 10 217 1 1 0 189 6 (-46)
2015-12-18 09:50:49,257 DEBUG RFM2Pi 682 NEW FRAME : OK 10 206 1 1 0 189 6 (-46)
2015-12-18 09:50:59,394 DEBUG RFM2Pi 683 NEW FRAME : OK 10 202 1 2 0 189 6 (-46)
2015-12-18 09:51:09,650 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 216 1 1 0 189 6 (-45)
2015-12-18 09:51:19,836 DEBUG RFM2Pi 684 NEW FRAME : OK 10 202 1 1 0 182 6 (-47)
2015-12-18 09:51:30,036 DEBUG RFM2Pi 685 NEW FRAME : OK 10 200 1 2 0 189 6 (-45)
2015-12-18 09:51:40,305 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 198 1 1 0 182 6 (-46)
2015-12-18 09:51:50,464 DEBUG RFM2Pi 686 NEW FRAME : OK 10 206 1 1 0 189 6 (-46)
2015-12-18 09:52:00,695 DEBUG RFM2Pi 687 NEW FRAME : OK 10 216 1 1 0 182 6 (-45)
2015-12-18 09:52:10,884 DEBUG RFM2Pi 688 NEW FRAME : OK 10 212 1 2 0 189 6 (-48)
2015-12-18 09:52:21,186 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 66 1 (-45)
2015-12-18 09:52:31,404 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 10 206 1 1 0 182 6 (-45)
2015-12-18 09:52:41,641 DEBUG RFM2Pi 689 NEW FRAME : OK 10 202 1 2 0 189 6 (-45)
I can check and post the transmitter code after the weekend, but basically its a mix of the examples available on the site; emonTx_Pulse and emontx_temperature_power.
Re: Emon not processing all frames from node
I agree a larger dataset is needed to make possible to recognize a pattern.
Is the emonTx v2 battery or AC powered?
How are the pulses being collected?
Is the RFM being put to sleep between sends?
Is the temp sensor just a regular ds18b20 ?
Can we see the sketch?
Since the packet and the crc do not match, the probability is one or the other is changed after it's set. The obvious (but IMO unlikely in this instance) is RF interference or poor signal etc. I don't think there are enough bits to suspect a "drift" especially if the issue is early in the packet.
The chances are something is happening to the packet after crc is set but before transmission in the sketch following the edit to add pulse counting. whether it's the pulse counting itself or just a consequence of the change I wouldn't like to say. My feeling is it's a misbehaving interrupt routine altering or the rfm not being ready to use (see emonTH Unreliable reading timing?) or another similar timing issue.
Paul
Re: Emon not processing all frames from node
@Bjotksta,
You could certainly drop the Tx power setting, even to minimum - there is plenty of signal there. Good for battery life if you are using and will eliminate one possible cause of packet corruption due to voltage sag
Re: Emon not processing all frames from node
Thanks for the inputs!
The node is powered via 5V USB.
The pulses are collected with a TSL257 in a home-built enclosure.
The temp sensor is a regular DS18B20.
Yes, the sketch is built up by the examples on github, which puts the RFM to sleep and wakes it up just before transmission without delay.
I also thought the interrupt routine may change the values between the CRC being calculated and transmission, so i modified it a bit after posting this thread, but there was no significant change. I even tried to send constant values, but without success.
Then I added a 120ms delay between wake-up of the RFM and the transmission (which seemed to be the cause in the thread regarding emonTH) and that made a huge difference. Since that moment I have not spotted a single disregarded frame!
I now have a working temperature sensor/energy consumption monitor!
Thanks for the help!
Re: Emon not processing all frames from node
I am also seeing many discarded frames. What exactly did you do to add the 120ms delay? ie what did you edit and where?
Re: Emon not processing all frames from node
Look in emontx_lib.ino, where the transmit function is:
void send_rf_data()
{
rf12_sleep(RF12_WAKEUP);
// if ready to send + exit loop if it gets stuck as it seems too
int i = 0; while (!rf12_canSend() && i<10) {rf12_recvDone(); i++;}
rf12_sendStart(0, &emontx, sizeof emontx);
// set the sync mode to 2 if the fuses are still the Arduino default
// mode 3 (full powerdown) can only be used with 258 CK startup fuses
rf12_sendWait(2);
rf12_sleep(RF12_SLEEP);
}
Add a delay ( delay(120); )
After
rf12_sleep(RF12_WAKEUP);
/Bjorksta
Re: Emon not processing all frames from node
I have found it but. What does it look like once done? same line ? next line? I have no idea how to write this stuff so thanks in advance.
Mine is emontx3.4 so a bit different.
Re: Emon not processing all frames from node
There are several different causes for packets being discarded due to crc failure. If you can post some of the discarded packets, it may be possible to confirm the actual cause. The fix used here is quite specific to the rf12 sleep routine affecting the next packet sent.
Is this in connection with the emonTx v3 you are posting about in another thread? If so, it is more likely to be due to the unused temp sensor circuits causing a long run of zero bits.
Paul
Re: Emon not processing all frames from node
I have zero discards from the older Pi with rf12 emontx3.2 firmware even though the emontx are at long distance from Pi. And lots of discards from new Pi rf69 emontx3.4 firmware with node really close..
Re: Emon not processing all frames from node
Could you post that as a longer text file - the single screen full is a bit limiting. What is shown are discarded noise packets (look at the signal strength in brackets at the end of the packet dump). The 'good' packets are way too strong - just fold the antenna up on the Tx side to get the strength below -30dBm
Re: Emon not processing all frames from node
Paul, This is the new pi2 with emon tx3.4 with firmware as supplied 2 weeks ago. So temp string is 300 for non existent ones. I get zero discards from old pi(with new firmware) and emontx3.2 with zeros in temp string even though the emontxs are at range extremities. The emontx3.4 is reporting signals of -30 on good packets due to the 2 units being side by side. too strong? I did consider hard wiring them together but purchasing without rf modules wasn't possible I was told.
Re: Emon not processing all frames from node
So are you actually missing any data ?
If so where are you seeing the data is missing? if in emoncms it may be a quirk of "fixed intervals" and you should check emonhub.log.
"discarded" packets are anything that didn't pass the crc checks, this includes anything that is received from other non-rfm devices eg a neighbors doorbell, baby monitors etc, plus any rfm packets from another group and occasionally some corrupted valid packets caused by issues including those mentioned above eg bitslip or the rf12 wakeup issue.
If there are lost packets to be retrieved we may be able to find the cause by studying the "discarded" packets, to do that we would need a sizeable chunk of actual data that can be manipulated, sorted and searched rather than a picture of a snippet. The first thing to be done would probably be to filter out anything with a very low RSSI as it can be assumed these are distant devices of no interest (unless debugging a weak signal of course) then patterns and similarities between valid and failed packets are studied.
If you do not want to use the RF search the term "serial-direct" on this forum, it is possible to not use the rf regardless of whether the emontx is available without a fitted rfm module.
Paul
Re: Emon not processing all frames from node
Thanks Paul,
Yes I saw the stuff about direct connection a little while back. That's what made me think of doing it because the devices are so close together in this instance. But when I discovered that the units came with rf anyway I decided to use rf.
What is interesting (I think) is that the older pi with 2 emontx3.2s and their firmware suffers zero discarded packets even though one emon tx is again 6 inches away from the pi and the other is 30yrds through 2 brick walls.
Re: Emon not processing all frames from node
I think it is the term "discarded" that maybe unhelpful. lets use the term "garbage", most of the time the "garbage" is just that, garbage, not abnormal and of zero interest. The older system seems to be operating as expected, 30 yards and 2 brick walls isn't an impossible ask and the fact you have no dropped packets confirms that. there will be a difference in received signal strength between the near and far devices but you cannot see that as it is an rfm12b based receiver, another brick wall or 5 more yards may of had different results and if you were finding the occasional dropped packet the first easy check may have been to try and reduce that span to reduce signal loss as a test, but you are not so all is well on that front.
The newer system which I also suspect is not losing any packets is a rfm69 based receiver so it is a more sensitive receiver and will not only see stronger and more "good packets" but also more "garbage" as it has a stronger listener. it is also a potentially noisier frequency depending on other tech you and you neighbors have. so it is not abnormal to see lots of garbage in the -90 to -100 RSSI range and some in the -70 to -80 but at this time you would only really be interested in any packets in say the 0 to -40 range IF you were trying to locate missing packets, otherwise there is unlikely to be anything of interest.
Paul


Règlement01
Zones
⏭ Green Zone includes PDM, Hospitals, Garages. You Cant Harm,Shoot,Carry,TakeHostage someone in Green Zone. Park your Cars in Right manner & Keep out from using Horn/Burnout
⏭ Blue Zone includes PD (Police Department) areas where extra protections are afforded to Police.
⏭ Red Zones includes Weed Farms and Weed, Coke, Meth and Opium Factory/Processing Areas.
Règlement 02
Combat-Login
⏭ You cant Disconnect from a RP situation without completing it. You cant Disconnect while in a Police Chase, Police Custody,Cell & Under Observation of Police even Respawn time is available.
⏭ Police have the right to stop,search and even Cuff someone if looked suspicious in a Cod red/ Robbery area. Normal citizens must not be in that area in such situations, or may fall into trouble.


Sharing projects in Pivot4D is easy. You control the users access and duration of time your audience has access to view any of your presentations. Share your content via the Pivot4D email tool. Users receive a unique URL address generated and sent via email through Pivot4D.


Example page header
Subtext for header
Example page header
Subtext for header
...
...
...
...
×
Close
Warning!
Better check yourself, you're not looking too good.


U-23 AFCON Ouster: Fans want Imama sacked
by Kelvin EkereteKelvin Ekerete
Nigerians have slammed the national U-23 side’s inability to qualify for the 2020 summer Olympics in Tokyo after failing to beat South Africa in their last Group B game.
The U-23 side recorded one win, a draw and a loss at the ongoing U-23 AFCON in Egypt which also doubles as the Olympics qualifier.
Nigeria lost their first match of the competition 1-0 to Ivory Coast before defeating Zambia 3-1 in their second group game needing a win against South Africa to secure passage to the semi-finals.
Ivory Coast topped the group with six points after defeating Zambia by a lone goal in the other group game with South Africa finishing second with five points, Nigeria is third with four points while Zambia finished the group with a point.
Reacting to the team’s failure to reach the semi-finals, Abenasports on Twitter said it is a shame how local coaches have failed to prove themselves with the job assigned to them.
“Flying Eagles failed, Golden Eaglets fumbled and now Dream Team VII. Shame!! Local coaches can’t prove themselves.”
Kenoke Atuegwu has called for the sack of the team’s coach, Imama Amapakabo.
“How can a coach perform woefully at three different tournaments? This is not coincidence; the man is bang below average and should be sacked immediately they come back from Egypt! This is too much to bear, and having in mind the Olympics is every four years, so it is till 2024.”
“Imama has set the worst record in the history of Nigerian football. He successfully crashed Nigeria out of three tournaments within a space of four weeks; WAFU, CHAN and U-23 AFCON,” commented Temitayo Ojotayo.
Afolabi Obe also called for the coach’s sack, “This is sad, Nigerians have just lost 70 percent interest in the next Olympics, probably one of the slim chances we had for a medal. Imama should not go near any national football team again.”
With the loss, Nigeria will not be represented in the football event of the Olympics after the Super Falcons also failed to book a spot.
Nigeria won a bronze medal at the last Olympic Games in Brazil.
Copyright PUNCH.
All rights reserved. This material, and other digital content on this website, may not be reproduced, published, broadcast, rewritten or redistributed in whole or in part without prior express written permission from PUNCH.
Contact: theeditor@punchng.com


Customer
Name
John Doe
Address
Wall Street
City
New York
Country
USA
Phone
2435444
Email
<EMAIL_ADDRESS>Comment
Comment
Back to Customers
Edit
Delete
Cars
Number Plate
Manufacturer
Model
Action
AAA-1234
Nissan
Pathfinder
Show
Edit
Delete
Add Car


const ( // AccessDenied indicates that the user does not have permission to perform the operation AccessDenied = "access denied" )
func WithErrorHandler(value fab.ErrorHandler) coptions.Opt
WithErrorHandler sets the error handler
func WithRefreshInterval(value time.Duration) coptions.Opt
WithRefreshInterval sets the interval in which the peer cache is refreshed
func WithResponseTimeout(value time.Duration) coptions.Opt
WithResponseTimeout sets the Discover service response timeout
ChannelService implements a dynamic Discovery Service that queries Fabric's Discovery service for information about the peers that are currently joined to the given channel.
type ChannelService struct {
// contains filtered or unexported fields
}
func NewChannelService(ctx contextAPI.Client, membership fab.ChannelMembership, channelID string, opts ...coptions.Opt) (*ChannelService, error)
NewChannelService creates a Discovery Service to query the list of member peers on a given channel.
func (s *ChannelService) Close()
Close releases resources
func (s ChannelService) GetPeers() ([]fab.Peer, error)
GetPeers returns the available peers
DiscoveryClient is the client to the discovery service
type DiscoveryClient interface { Send(ctx context.Context, req *discclient.Request, targets ...fab.PeerConfig) ([]fabdiscovery.Response, error) }
DiscoveryError is an error originating at the Discovery service
type DiscoveryError error
LocalProvider implements a local Dynamic Discovery LocalProvider that queries Fabric's Discovery service for information about the peers that are in the local MSP.
type LocalProvider struct {
// contains filtered or unexported fields
}
func NewLocalProvider(config fab.EndpointConfig, opts ...coptions.Opt) *LocalProvider
NewLocalProvider creates a new local dynamic discovery provider
func (p *LocalProvider) Close()
Close will close the cache and all services contained by the cache.
func (p *LocalProvider) CloseContext(ctx fab.ClientContext)
CloseContext frees resources and caches for the given context.
func (p *LocalProvider) CreateLocalDiscoveryService(mspID string) (fab.DiscoveryService, error)
CreateLocalDiscoveryService returns a local discovery service
LocalService implements a dynamic Discovery Service that queries Fabric's Discovery service for the peers that are in the local MSP.
type LocalService struct {
// contains filtered or unexported fields
}
func (s *LocalService) Close()
Close releases resources
func (s LocalService) GetPeers() ([]fab.Peer, error)
GetPeers returns the available peers
func (s *LocalService) Initialize(ctx contextAPI.Local) error
Initialize initializes the service with local context


Functions for the hyperbolic and related distributions. Density, distribution and quantile functions and random number generation are provided for the hyperbolic distribution, the generalized hyperbolic distribution, the generalized inverse Gaussian distribution and the skew-Laplace distribution. Additional functionality is provided for the hyperbolic distribution, normal inverse Gaussian distribution and generalized inverse Gaussian distribution, including fitting of these distributions to data. Linear models with hyperbolic errors may be fitted using hyperblmFit.
| Version: | 0.8-4 |
| Depends: | R (≥ 3.0.1) |
| Imports: | DistributionUtils, MASS |
| Suggests: | VarianceGamma, actuar, SkewHyperbolic, RUnit |
| Published: | 2018-05-15 |
| Author: | David Scott |
| Maintainer: | David Scott <d.scott at auckland.ac.nz> |
| License: | GPL-2 | GPL-3 [expanded from: GPL (≥ 2)] |
| URL: | https://r-forge.r-project.org/projects/rmetrics/ |
| NeedsCompilation: | no |
| Materials: | NEWS ChangeLog |
| In views: | Distributions |
| CRAN checks: | GeneralizedHyperbolic results |
| Reference manual: | GeneralizedHyperbolic.pdf |
| Package source: | GeneralizedHyperbolic_0.8-4.tar.gz |
| Windows binaries: | r-devel: GeneralizedHyperbolic_0.8-4.zip, r-release: GeneralizedHyperbolic_0.8-4.zip, r-oldrel: GeneralizedHyperbolic_0.8-4.zip |
| OS X binaries: | r-release: GeneralizedHyperbolic_0.8-4.tgz, r-oldrel: GeneralizedHyperbolic_0.8-4.tgz |
| Old sources: | GeneralizedHyperbolic archive |
| Reverse imports: | NormalLaplace, SkewHyperbolic, VarianceGamma, Wrapped |
| Reverse suggests: | DistributionUtils, fitdistrplus, fitteR |
Please use the canonical form https://CRAN.R-project.org/package=GeneralizedHyperbolic to link to this page.


You've saved £234.18 by not spending this week.
Your miniumum montly payment this month is £18.12 rather than £36.19.
You spend most at 10pm and 2pm.


This dialog shows messages related to important game events, such as faction defeat or victory.
Any messages shown in this dialog will also appear in the Event View panel, and are recorded in the Command History for later examination.


Sharon Crushes Netanyahu Israeli prime minister retains leadership of the Likud Party with about 60% of the vote. The celebrations are muted amid terrorist attacks.
Army, Rumsfeld Do Battle A light-armor program is spared, but the service's role in modern warfare is an issue.
Taking Up the Cause of High Expenses The Supreme Court is stepping into the battle over how much telemarketing firms can keep of the funds they raise for charity.


|
Français Video, links, etc
Home
|
Sunday, May 4, 2014
|
||
|
"Laura Risk's fiddle is a revelation and
achingly beautiful."
Ric Goldman
and friends
— Ken Burns, filmmaker Ric, who called at our Klez Contra 4, is well known as a caller and dancer in California's contra, English country dance, and Morris dance communities. He's living in Montreal now. Yeah! Guest callers: Guillaume Bourque and Sean McCutcheon.
Ukrainian Hall
6:30 pm - 7 pm: Introductory session. Recommended
for new dancers.
|


Nine out of ten startups fail in the first year. Why? More important, what can we do to improve the odds? Entrepreneur Steve Blank might have an answer, expressed in his book The Four Steps to the Epiphany. Key points from the book are summarized here.
Ignite Chicago
This presentation was created for Ignite Chicago. Ignite talks are special because speakers are required to present their thoughts in five minutes with slides that auto-advance every fifteen seconds. Thank you Stella Fayman and Tim Jahn for organizing the event.
About the Author of The Four Steps to the Epiphany
Steve Blank worked in, owned, or managed eight different silicon valley startups in the course of twenty years. His eighth startup was very successful; he was able to exit with enough money to retire. At that point, Blank began to reflect on the successes and failures of the various startups he had been involved with. Reflection led to lectures at Stanford, Berkeley, and Columbia. Notes from his lectures evolved into the book: The Four Steps to the Epiphany.
Blank noticed that startups went through predictable patterns of success or failure. Yes, there are multiple paths to failure, but there are fewer paths to success. Blank believes he has found a success path that applies to most startups.
Counter Example: Webvan
Sometimes it helps to explain an idea through counter example. Webvan was built to deliver groceries to people who ordered on the web. The problem? Webvan built software and warehouses before they had a reliable supply of customers. They were so confident of their future success that they spent close to one billion dollars building infrastructure. They ran out of money before they had customers.
It’s not fair to pick on Webvan when so many other companies make the same mistake. Remember the Apple Newton? Apple is a great company, but they put tons of money into an early PDA (the Newton) before customers even knew what a PDA was. Same with Motorola. Motorola’s Iridium was supposed to be a network of communications satellites covering the planet. Satellites designed to give internet and phone access to every human on planet earth. The problem: Nobody could afford Iridium. In these examples, Motorola, Apple, and Webvan, all burned through money before they had a steady supply of customers. There is a better way.
The Four Steps
Steve Blank lists The Four Steps to the Epiphany as:
- Customer Discovery
- Customer Validation
- Customer Creation
- Company Building
There are a few things to point out about the steps. First the process is iterative, not linear. If at any point we get stuck, we go back and repeat a step (or two) based on what we’ve learned. A smaller repetition might be termed an iteration. But if the entrepreneur needs to revisit the entire business plan, or change basic assumptions in the business model, the repetition/backtracking would be termed a pivot.
Customer Discovery and the Minimum Viable Product
Every entrepreneur has an idea about what customers want. We all know something of the pain felt by our customers, or so we think. Blank’s suggestion: Take what you know about your prospective customers’ pain and build a minimum viable product (MVP) with just enough features to address the pain. Then get outside the building. Get away from wherever it is that you work and talk to real customers with your MVP in hand. Let them try it. They’ll give you valuable feedback about what you should do next. If their pain is great enough, and if your MVP is good enough, they’ll buy it.
Which Customers?
It’s important to note the type of customer we want at this stage. We want early adopters. We want customers who are feeling pain in the entrepreneur’s area of expertise. Perhaps customers who have tried to solve the problem themselves with no success. Early adopters will give us the most useful & actionable feedback at this stage.
Customer Validation
The customer validation step is complete when early adopters buy the product we’re offering. When customers buy, we know we have a valid product. If they don’t buy, it might be time to pivot. In this context, pivot means to change the basic assumptions of the business we’re building. We might change pricing, features, or we might change our entire approach to customers. Many startups go through several pivots before achieving success.
Customer Creation
After we’ve discovered customers, and after we’ve gone through customer validation, it’s time to create more customers. Our initial customers were the early adopters and innovators. In the customer creation step, we move beyond our initial customers into the majority. At this point we begin to spend money on marketing.
Company Building
After we’ve gone through the first three customer-oriented steps, we build the company. Now it’s time to spend money on infrastructure, warehouses, expensive customized software… anything we need to scale the company as large as we can. Notice that we don’t try to scale until after we figure out how to develop a steady supply of customers.
That’s Not All…
We live in a time of continuous & rapid change. Once a business has become successful with The Four Steps, it’s important to remain watchful for new opportunities. Good companies become great when they execute consistently over time.
Note: A version of this post originally appeared on the WisdomGroup Blog.


About Us
The purpose of Néo-Noise is to give the user an immersive auditorial experience of New York City. We wanted to create a website that would be able to capture the bustling city in its full glory without leaving the safety of your home.
Made by the creators of Néo-Manhattan, this web application offers a way for you to personalize every sound to your tastes. Feel free to experiment with the audio levels of each sound to find the perfect urban symphony for you. The website will be updated regularly to introduce different areas in NYC by using sounds captured in the specific area we are trying to replicate.


{% extends '_layouts/layout.html' %} {% block page_title %} {% if practiceName %} Register with {{ practiceName }} {% else %} {{serviceName}} {% endif %} {% endblock %} {% block content %}
Use NHS.ID to register with {{ practiceName }}
NHS.ID is a scheme to fight the growing problem of online identity theft.
It’s secure, and stops someone from pretending to be you.
If you have not used NHS.ID before, it will take you about 10 minutes to get set up. You can access other NHS services securely wherever you see the NHS.ID logo.
If you don’t have an NHS.ID you’ll need to provide:
It will help {{ practiceName }} find your medical records if you’re able to provide as much information as you can. This could include:
An NHS number is a 10 digit number, for example:<PHONE_NUMBER>
You can find your NHS number:
You can still register without this information.


| This inspection reports any instances of assignment to a variable declared as a JavaScript for loop parameter. While occasionally intended, this construct can be extremely confusing, and is often the result of a programmer error. |
| Powered by InspectionJS |


Form Validator
© Peter Bakondy @
Github
@
Twitter
User registration form example
Username
Email address
Credit card number
Security Code
Show Registered Usernames
Show Registered Email Addresses


Exim Bank expands its wings to Ethiopia
by The Citizen ReporterIn Summary
The bank is now operating in five markets across Eastern Africa; Tanzania, Union of the Comoros, Djibouti and Uganda.
Dar es Salaam. Exim Bank Group will become the first Tanzanian financial institution to start operations in Ethiopian market, establishing a foothold in the Africa’s second most populous country and extending its African network to 5 countries.
According to a statement released by the bank in Dar es Salaam yesterday, the bank has obtained a license to open and have an Exim Bank Representative Office in Ethiopia through its Djibouti subsidiary and it plans to start operating soon.
“Our Commercial Representative Office is expected to be fully operational in December 2019 at Zouleka LKG Building, 2nd floor, Sub City Bole, 2160/B. Addis Ababa.)’’ Mr Jaffari Matundu, the bank’s Chief Executive Officer, said in the statement.
The bank is now operating in five markets across Eastern Africa; Tanzania, Union of the Comoros, Djibouti and Uganda.
He said the expansion to the country comes as part of the Group’s strategic expansion plans in pursuit of our aspiration of becoming a Pan African Bank.
He said the representative office will foster strategic initiatives in increasing cooperation with African countries and provides a valuable platform for the Bank to market its differentiated and customized services to overseas businesses.
Advertisement
“This is an important milestone for Exim Bank Group,’’ he said.


--- title: Drupal default themes suffering from divitis and classitis excerpt: 'Checking #Drupal theming and boy, those default themes are suffering from chronic divitis/classitis! So bloated that it makes me miss #MODx.' date: '2010-04-15 12:15:24 +0200' date_gmt: '2010-04-15 10:15:24 +0200' categories: - Webdev tags: - tweets - web - design - development ---
Checking #Drupal theming and boy, those default themes are suffering from chronic divitis/classitis! So bloated that it makes me miss #MODx. Luckily the output can be customised in template.php.


EventStreamProvider<T extends Event>
class
class EventStreamProvider<T extends Event> {
final String _eventType;
const EventStreamProvider(this._eventType);
Stream<T> forTarget(EventDispatcher target, {bool useCapture: false}) {
return target._getEventStream(_eventType, useCapture);
}
String get eventType => _eventType;
}
Constructors
const EventStreamProvider(String _eventType) #
Creates a new Object instance.
Object instances have no meaningful state, and are only useful
through their identity. An Object instance is equal to itself
only.
docs inherited from Object
const EventStreamProvider(this._eventType);
Properties
final String eventType #
String get eventType => _eventType;
Methods
Stream<T> forTarget(EventDispatcher target, {bool useCapture: false}) #
Stream<T> forTarget(EventDispatcher target, {bool useCapture: false}) {
return target._getEventStream(_eventType, useCapture);
}


Food Fetch is a platform that allows homeless shelters to access more nutritious food at a lower cost, while providing grocery stores an incentive to reduce their food waste by making a profit on the products they would’ve otherwise thrown out.
In 2016 The Ottawa Food Bank allocated $60-thousand dollars to buy fresh produce over the winter months, but come January, all the funds were almost completely used up. This meant that they had to cut down on funding for other services they provided.


This webpage is currently under development, and I am looking forward to showcasing my coding work here.
I have interests and experience in the technological, scientific, and financial domains. To keep up with the state of code, I spend time on Stack Overflow
I enjoy coding in Python and practiced doing so on Project Euler problems. They have a lot of fun number theory problems, and due to the numeric nature of the problems, I have been able to use Numpy to accelerate my solutions.
In addition, I have also brushed up on C++ using the Timus Online Judge. Most of the problems that I have solved on that site are on the easy side to just get used to the site. Problem #1220 "Stacks" required a bit of extra thinking about the overhead incurred at the lower level with respect to class design.
While my research work at Pitt was using statistical mechanical molecular modeling techniques in surface science and have analyzed scientific simulation data, I have developed an interest in the machine learning approach to statistical analysis. I have recently finished Andrew Ng's Machine learning course on Coursera. In addition, I am taking Practical Machine Learning and Developing Data Products from Johns Hopkins University on Coursera and will soon have Shiny app to demo here!
Check out my github. This website is hosted using Github Pages.
I will have a link to my resume here soon.
Demos and links to my work will appear here soon. You can expect


Chester Devs Presentations
Date
Presentation
By
06/07/2016
AWS Elastic Beanstalk and Docker
Thomas Redstone


All you need to empower your workflow and productivity
We offer you solutions for any question regarding data processing and automation of your business.We adapt the solutions to all domanins adding stability to your business.
The best expertise on Forestry and GIS recomend us for the best Forestry Management System with secure and powerfull softwares.
Wide range of technologies and platforms used for your business success fitting custom needs.


{% extends "base.html" %} {% block content %} Unhuman is Subversion Sid Arcidiacono Leave your preconceptions here. Welcome to Unhuman, the stripping away of Self through use of sacred symbols, and the exploration of deconstruction. About Contact {% endblock %}
Leave your preconceptions here.
Welcome to Unhuman, the stripping away of Self through use of sacred symbols, and the exploration of deconstruction.


This version of the documentation is a quick and dirty collection of the available documentation. It contains errors, references to obsolete constructs, limitations that have been removed, etc.
The library(jpl)
provides a bidirectional interface to a
Java Virtual Machine.
'java.lang.String'
'[I'
or 'Ljava.lang.String;'
class(_,_)
or array(_)
,
e.g. class([java,util],['Date'])
If X is an object (non-array) type or descriptor and Params is a list of values or references, then V is the result of an invocation of that type's most specifically-typed constructor to whose respective formal parameters the actual Params are assignable (and assigned).
If X is an array type or descriptor and Params is a list of values or references, each of which is (independently) assignable to the array element type, then V is a new array of as many elements as Params has members, initialised with the respective members of Params.
If X is an array type or descriptor and Params is a non-negative integer N, then V is a new array of that type, with N elements, each initialised to Java's appropriate default value for the type.
If V is {Term} then we attempt to convert a new org.jpl7.Term instance to a corresponding term; this is of little obvious use here, but is consistent with jpl_call/4 and jpl_get/3.
<jref>(1552320)
(for
static or instance methods)
'java.util.Date'
(for static
methods only)
'Ljava.util.Date;'
(for static
methods only)
class([java,util],['Date'])
(for static
methods only)
MethodName should be a method name (as an atom) (may involve dynamic overload resolution based on inferred types of params)
Params should be a proper list (perhaps empty) of suitable actual parameters for the named method.
The class or object may have several methods with the given name; JPL will resolve (per call) to the most appropriate method based on the quantity and inferred types of Params. This resolution mimics the corresponding static resolution performed by Java compilers.
Finally, an attempt will be made to unify Result with the
method's returned value, or with @(void)
if it has none.
Fspec can be
Finally, an attempt will be made to unify V with the retrieved value or object reference.
Examples
jpl_get('java.awt.Cursor', 'NE_RESIZE_CURSOR', Q). Q = 7. jpl_new(array(class([java,lang],['String'])), [for,while,do,if,then,else,try,catch,finally], A), jpl_get(A, 3-5, B). B = [if, then, else].
X can be
class(_,_)
or array(_)
type (for static fields)
Fspec can be
V must be a suitable value or object.
['-Xrs']
Fails silently if a JVM has not yet been started, and can thus be used to test for this.
jpl.pl
) of JPL.
It should exactly match the version identifiers of JPL's C (jpl.c) and Java (jpl.jar) components.
Example
?- jpl_pl_lib_version(V). V = '7.4.0-alpha'.
It should exactly match the version identifiers of JPL's Prolog (jpl.pl
)
and Java (jpl.jar) components.
Example
?- jpl_c_lib_version(V). V = '7.4.0-alpha'.
ClassName is its canonical (?) source-syntax (dotted)
name, e.g. 'java.util.Date'
NB not used outside jni_junk and jpl_test (is this (still) true?)
NB oughta use the available caches (but their indexing doesn't suit)
NB should ensure that, if not found in cache, then cache is updated.
Intriguingly, getParameterTypes returns class objects (undocumented AFAIK) with names 'boolean', 'byte' etc. and even 'void' (?!)
'java.lang.String'
Class is a (canonical) reference to the corresponding class object.
NB uses caches where the class is already encountered.
Type is its corresponding JPL type structure, e.g. class([java,util],['Date'])
, array(class([java,util],['Date']))
, array(long)
NB by "classname" do I mean "typename"?
NB should this throw an exception for unbound CN? is this public API?
Type is the unique most specialised type of which Datum denotes an instance;
NB 3 is an instance of byte, char, short, int and long, of which byte and char are the joint, overlapping most specialised types, so this relates 3 to the pseudo subtype 'char_byte';
Class is a (canonical) reference to the (canonical) class object which represents the class of Object
NB what's the point of caching the type if we don't look there first?
Type is the JPL type of that object.
?- setof(Type, jpl_primitive_type(Type), Types). Types = [boolean, byte, char, double, float, int, long, short].
Type is its type.
jFindClass throws an exception if FCN can't be found.
e.g. jpl_type_to_classname(class([java,util],['Date']), 'java.util.Date')
java.lang.Class
.@(false)
, the JPL representation
of the Java boolean value 'false'.@(null)
, the JPL representation
of Java's 'null' reference.NB this checks only syntax, not whether the object exists.
@(true)
, the JPL representation
of the Java boolean value 'true'.@(void)
, the JPL representation
of the pseudo Java value 'void' (which is returned by jpl_call/4
when invoked on void methods).
NB you can try passing 'void' back to Java, but it won't ever be interested.
@(false)
, the JPL representation of the
Java boolean value 'false'.
@(null)
, the JPL representation of Java's
'null' reference
@(true)
, the JPL representation of the Java
boolean value 'true'.
@(void)
, the JPL representation of the
pseudo Java value 'void'
Length is the length of that array.
This is a utility predicate, defined thus:
jpl_array_to_length(A, N) :- ( jpl_ref_to_type(A, array(_)) -> jGetArrayLength(A, N) ).
Elements is a Prolog list of JPL representations of the array's elements (values or references, as appropriate).
This is a utility predicate, defined thus:
jpl_array_to_list(A, Es) :- jpl_array_to_length(A, Len), ( Len > 0 -> LoBound is 0, HiBound is Len-1, jpl_get(A, LoBound-HiBound, Es) ; Es = [] ).
NB this fails silently if
Enumeration
interface.
Elements is a Prolog list of JPL references to the enumerated objects.
This is a utility predicate, defined thus:
jpl_enumeration_to_list(Enumeration, Es) :- ( jpl_call(Enumeration, hasMoreElements, [], @(true)) -> jpl_call(Enumeration, nextElement, [], E), Es = [E|Es1], jpl_enumeration_to_list(Enumeration, Es1) ; Es = [] ).
NB String is converted to atom but Integer is presumably returned as an object ref (i.e. as elsewhere, no auto unboxing);
NB this is anachronistic: the Map interface is preferred.
java.util.Iterator
interface.
Element is the JPL representation of the next element in the iteration.
This is a utility predicate, defined thus:
jpl_iterator_element(I, E) :- ( jpl_call(I, hasNext, [], @(true)) -> ( jpl_call(I, next, [], E) ; jpl_iterator_element(I, E) ) ).
If Datums have a most specific common supertype, then Array is a JPL reference to a new Java array, whose base type is that common supertype, and whose respective elements are the Java values or objects represented by Datums.
Array is a JPL reference to a new Java array of org.jpl7.Term, whose elements represent the respective members of the list.
java.util.Map
interface
This generates each Key-Value pair from the Map, e.g.
?- jpl_call('java.lang.System', getProperties, [], Map), jpl_map_element(Map, E). Map = @<jref>(0x20b5c38), E = 'java.runtime.name'-'Java(TM) SE Runtime Environment' ; Map = @<jref>(0x20b5c38), E = 'sun.boot.library.path'-'C:\\Program Files\\Java\\jre7\\bin' etc.
This is a utility predicate, defined thus:
jpl_map_element(Map, K-V) :- jpl_call(Map, entrySet, [], ES), jpl_set_element(ES, E), jpl_call(E, getKey, [], K), jpl_call(E, getValue, [], V).
java.util.Set
interface.
On backtracking, Element is bound to a JPL representation of each element of Set.
This is a utility predicate, defined thus:
jpl_set_element(S, E) :- jpl_call(S, iterator, [], I), jpl_iterator_element(I, E).


Dear marketing friend,
Did you know that there
are simple, proven strategies that you can use to
break the $10,000 dollar mark over and over again?
Inside this special report you'll discover simple fact's, tip's and
proven strategies that will help you blow past the magical “six
figures a year” milepost…and start making $10,000 a
month online!
This
Report Comes with Private Label Rights
The best part is with the
private label rights to this report not only will you be
able to learn how you can get
on the path to making $10,000 dollars online, you will be able to pass that
knowledge on to your customers and subscribers. You will be
providing them with quality information that
will help them understand the basics strategies that
they can use to hit
the $10,000 dollar mark online.
The report is completely
customizable. You will be able to add in your own
contact information, product and service recommendations
and links to your favorite affiliate programs. I'm even
including a ready to go to squeeze page confirmation
page and sales page, so that you can get set up quickly
and easily!
Click
here to see some full sized examples
In this report
you'll be able to provide your subscribers
with great information that they can actually use!
You will teach
them...
-
How to Team Up With Other
Marketers For Fast Profits!
-
How You Can Type Your Way to
$10,000!
-
How to Tap Into the Backend
Profits Automatically!
-
How to Really Take Advantage of
eBay!
-
How Targeting Other Marketers Can
Make You a Fortune!
And that's just the beginning. Once
they sign up for the "Ten Ways to Make $10 Thousand Dollars Online" Short
Report they will have access to
great information that will get them started on
the path to making $10,000 dollars online and they
will thank you for it!
|
What's
Included in the....
"Ten Ways to Make $10 Thousand Dollars Online"
Short Report Package?
With this report
you will providing 23 quality pages packed full
(over 6000 words) of solid
information that you and your subscribers can start using to immediately impact
your business! The "Ten Ways to Make $10 Thousand Dollars Online" Short
Report package contains everything you need to start using
and selling it right away, including:
|
- A copy of this sales page
- 1 ready to go download page
- 23 Page customizable
report
- 1 ready to go squeeze page
- 1 ready to go thank you page
- A complete graphic package
- + the editable PSD graphics
---Edit
these links --
- Squeeze Page -
Click
here to see it
(in
a new window)
- Conformation Page
-
Click
here to see it
(in a
new window)
- Download Page -
Click
here to see it
(in a
new window)
- Complete Graphics
Package -
- Including
Editable PSD Files -
All ready to Add
Your Links & Go!
|
|
Remember, this short
report comes with
resale rights so you can edit this entire report and use it for yourself or package it up and sell it and
keep all the profits!
Here's
How To Order To Right Now!
It doesn't
matter if it's 3:00 am you will get instant access to this
material. Once your payment is approved, you will be taken to
a special download page where you will have instant access to
the Ten Ways to Make $10,000 Dollars Online including all of the sales
material, webpages and the custom graphics package.
So what
are you waiting for? Grab the "Ten Ways to Make $10 Thousand Dollars Online"
Short
Report complete with
resale rights today and
start profiting from it
right away!
With
This Special Offer
Only For The First 20 People
$7.97
*After the
first 20 sales the price will immediately
increase to $9.97 or more!
Remember with this
report you can add your own name as the
author, educate your subscribers or resell it, and keep 100% of the profits for
yourself!
Your Name
PS.
Don't forget that I've
included the .psd files for all the graphics, so you can
change the look and feel of the report to your liking.
PSS. And the ready to go squeeze page,
confirmation page and sales page, so that you can get set up
quickly and easily!
|


1. Command Line Arguments¶
1.1. Usage¶
noodles <command_type> <path_to_spec> [optional_arguments]
1.2. Positional Arguments¶
-
<command_type>
¶
The command type.
The command type is a user-defined key under the following items in the spec file:
<top_level>.depends_on
<top_level>.requirements
<top_level>.commands
<top_level>.write_outputs
Where
<top_level>
can be one of the following top level keys in the spec:experiment_default
before_all_experiments[i]
experiments[i]
after_all_experiments[i]
i
can be any index.- Example
The following code specifies the command type
lets_do_it
:experiments: - name: run_script.exp1 description: Run the script after uploading the script to the remote server envs: SCRIPT: exp1.sh depends_on: lets_do_it: - upload.exp1 requirements: lets_do_it: - memory_usage: "<=0.5" commands: lets_do_it: - "cd $HOME" - "bash $SCRIPT" write_outputs: lets_do_it: stdout_to: $LOCAL_DIR/exp1.stdout.log stderr_to: $LOCAL_DIR/exp1.stderr.log
-
<path_to_spec>
¶
Path to the spec file.
- Example
specs/train.yml
1.3. Optional Arguments¶
-
-h
,
--help
¶
Show the help message and exit.
-
-v
,
--verbose
¶
Print out verbose messages.
If this option is used, verbose messages regarding to what Noodles is doing will be printed.
-
-d
,
--debug
¶
Print out debug messages.
If this option is used, the following things will be printed:
Command line arguments used
Original user spec
Processed user spec
Creation of temporary files
Commands written to temporary files
The commands to be run by Noodles
Environment variables added by Noodles
-
-s
,
--silent
¶
Silence all logging messages.


Kon'nichiwa!!! We are AnimeWorld, Lets explore the world of Anime. Lets get through some of the interesting anime series and escape from the reality.
Japanese culture is fascinating, and anime is one of the best ways to learn about. You will learn so much more than you imagine, including the folklore and myths of the country, as well as popular traditions and commonly used words into Japan.
Artisitic talents are showcased in the anime. Anime provides a massive catalog of characters because of the ability to perform in any fictional setting. Characters can vary from high school student and space cowboys to demons, samurais, ninjas, pirates, detectives, ghosts, and gods.
The character has a depth detailing even in appearance and also in the character development of the character. The action season will make your jaw drop and your eyes pop.
Common misconception that anime is only for children and cartoon. This could not be further from the truth. It is suitable for all ages. While there are some anime shows that are aimed at children, there are also those that appeal to adults, as they deal with mature themes, including violence, morality, and death.
Animated 2D characters with high level detailing
Story relates to the real life
Learn characters and life values and follow them in real life
$399/ month
Price Per Month is $33.25
$599/ month
Price Per Month is $49.25


Using Neural Networks to predict wine type & quality based on chemical properties.
Predicting Wine: Artificial Neural Networks with Keras
Using Artificial Neural Networks to predict wine type and quality based on its chemical properties.
1. About Deep Learning
Deep Learning
Deep Learning, a.k.a. Artificial Neural Networks (ANN), is a subfield of machine learning that is a set of algorithms that are inspired by the structure and function of the brain and is a popular fields in data science with many case studies involving robotics, image recognition and Artificial Intelligence (AI).
One of the most powerful Python libraries for developing and evaluating deep learning models is Keras; It wraps the efficient numerical computation libraries Theano and TensorFlow.
Perceptrons
The “perceptron” is a neural network, which, in its simplest form, consists of a single neuron. Much like biological neurons, that have dendrites and axons, the single artificial neuron is a simple tree structure that has input nodes and a single output node, and is connected to each input node.
Here’s a visual comparison of the two:
There are six components to artificial neurons. From left to right, they are:
-
Input nodes
. Each input node is associated with a numerical value, which can be any real number. -
Connections
. Each connection that departs from the input node has a weight associated with it and this can also be any real number. -
All the values of the input nodes and weights of the connections are brought together: they are used as inputs for a
weighted sum
. -
The result will be the input for a
transfer
oractivation function
. -
As a result, we have the
output node
, which is associated with the function (such as the sigmoid function) of the weighted sum of the input nodes. -
Finally, the
bias
, which we can actually consider as the weight associated with an additional input node that is permanently set to 1. The bias value is important because it allows us to shift the activation function to the left or right, which can determine the success of our learning.
The logical consequence of this model is that perceptrons only work with numerical data. This means that we need to convert any nominal data into a numerical format.
The perceptron can be used for classification purposes to determine that any output above a certain treshold indicates that an instance belongs to one class, while an output below the treshold might result in the input being a member of the other class. The straight line where the output equals the treshold is then the boundary between the two classes.
Multi-Layer Perceptrons
Networks of perceptrons are multi-layer perceptrons, and this is what we will implement in Python with the help of Keras. Multi-layer perceptrons are also known as “feed-forward neural networks”. These are more complex networks than the perceptron, as they consist of multiple neurons that are organized in layers. The number of layers is usually limited to two or three, but theoretically, there is no limit.
The layers act very much like the biological neurons, the outputs of one layer serve as the inputs for the next layer.
Among the layers, we can distinguish an input layer, hidden layers and an output layer. Multi-layer perceptrons are often fully connected. This means that there’s a connection from each perceptron in a certain layer to each perceptron in the next layer.
While the perceptron could only represent linear separations between classes, the multi-layer perceptron overcomes that limitation and can also represent more complex decision boundaries.
2. The Data
Can we predict whether a wine is red or white by looking at its chemical properties?
The data consists of two datasets that are related to red and white variants of the Portuguese “Vinho Verde” wine. Below is the Data Dictionary for the 12 variables that are included in the data:
Fixed acidity
: acids are major wine properties and contribute greatly to the wine’s taste. Usually, the total acidity is divided into two groups: the volatile acids and the nonvolatile or fixed acids. Among the fixed acids that we can find in wines are the following: tartaric, malic, citric, and succinic. This variable is expressed in g(tartaricacidtartaricacid)/dm3dm3 in the data sets.Volatile acidity
: the volatile acidity is basically the process of wine turning into vinegar. In the U.S, the legal limits of Volatile Acidity are 1.2 g/L for red table wine and 1.1 g/L for white table wine. In these data sets, the volatile acidity is expressed in g(aceticacidaceticacid)/dm3dm3.Citric acid
is one of the fixed acids that we will find in wines. It’s expressed in g/dm3dm3 in the two data sets.Residual sugar
typically refers to the sugar remaining after fermentation stops, or is stopped. It’s expressed in g/dm3dm3 in the red and white data.Chlorides
can be a major contributor to saltiness in wine. Here, we will see that it’s expressed in g(sodiumchloridesodiumchloride)/dm3dm3.Free sulfur dioxide
: the part of the sulphur dioxide that is added to a wine and that is lost into it is said to be bound, while the active part is said to be free. Winemaker will always try to get the highest proportion of free sulphur to bind. This variables is expressed in mg/dm3dm3 in the data.Total sulfur dioxide
is the sum of the bound and the free sulfur dioxide (SO2). Here, it’s expressed in mg/dm3dm3. There are legal limits for sulfur levels in wines: in the EU, red wines can only have 160mg/L, while white and rose wines can have about 210mg/L. Sweet wines are allowed to have 400mg/L. For the US, the legal limits are set at 350mg/L and for Australia, this is 250mg/L.Density
is generally used as a measure of the conversion of sugar to alcohol. Here, it’s expressed in g/cm3cm3.pH
or the potential of hydrogen is a numeric scale to specify the acidity or basicity the wine. As we might know, solutions with a pH less than 7 are acidic, while solutions with a pH greater than 7 are basic. With a pH of 7, pure water is neutral. Most wines have a pH between 2.9 and 3.9 and are therefore acidic.Sulphates
are to wine as gluten is to food. We might already know sulphites from the wine have been known to cause headaches. They are a regular part of winemaking and are considered necessary to produce wine. In this case, they are expressed in g(potassiumsulphatepotassiumsulphate)/dm3dm3.Alcohol
: wine is an alcoholic beverage and as we know, the percentage of alcohol can vary from wine to wine. It’s expressed as % vol in the red and white data.Quality
: wine experts graded the wine quality between 0 (very bad) and 10 (very excellent). The eventual number is the median of at least three evaluations made by those same wine experts.
# Import numpy
import numpy as np
# Import pandas
import pandas as pd
# Read in white wine data
white = pd.read_csv("http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv", sep=';')
# Read in red wine data
red = pd.read_csv("http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv", sep=';')
3. Exploratory Data Analysis
# Print info on white wine
print("White Wine:")
print(white.info())
# Print info on red wine
print("\n""Red Wine:")
print(red.info())
White Wine:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4898 entries, 0 to 4897
Data columns (total 12 columns):
fixed acidity 4898 non-null float64
volatile acidity 4898 non-null float64
citric acid 4898 non-null float64
residual sugar 4898 non-null float64
chlorides 4898 non-null float64
free sulfur dioxide 4898 non-null float64
total sulfur dioxide 4898 non-null float64
density 4898 non-null float64
pH 4898 non-null float64
sulphates 4898 non-null float64
alcohol 4898 non-null float64
quality 4898 non-null int64
dtypes: float64(11), int64(1)
memory usage: 459.3 KB
None
Red Wine:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1599 entries, 0 to 1598
Data columns (total 12 columns):
fixed acidity 1599 non-null float64
volatile acidity 1599 non-null float64
citric acid 1599 non-null float64
residual sugar 1599 non-null float64
chlorides 1599 non-null float64
free sulfur dioxide 1599 non-null float64
total sulfur dioxide 1599 non-null float64
density 1599 non-null float64
pH 1599 non-null float64
sulphates 1599 non-null float64
alcohol 1599 non-null float64
quality 1599 non-null int64
dtypes: float64(11), int64(1)
memory usage: 150.0 KB
None
View the first 5 rows of red
:
red.head()
| fixed acidity | volatile acidity | citric acid | residual sugar | chlorides | free sulfur dioxide | total sulfur dioxide | density | pH | sulphates | alcohol | quality | type | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 7.4 | 0.70 | 0.00 | 1.9 | 0.076 | 11.0 | 34.0 | 0.9978 | 3.51 | 0.56 | 9.4 | 5 | 1 |
| 1 | 7.8 | 0.88 | 0.00 | 2.6 | 0.098 | 25.0 | 67.0 | 0.9968 | 3.20 | 0.68 | 9.8 | 5 | 1 |
| 2 | 7.8 | 0.76 | 0.04 | 2.3 | 0.092 | 15.0 | 54.0 | 0.9970 | 3.26 | 0.65 | 9.8 | 5 | 1 |
| 3 | 11.2 | 0.28 | 0.56 | 1.9 | 0.075 | 17.0 | 60.0 | 0.9980 | 3.16 | 0.58 | 9.8 | 6 | 1 |
| 4 | 7.4 | 0.70 | 0.00 | 1.9 | 0.076 | 11.0 | 34.0 | 0.9978 | 3.51 | 0.56 | 9.4 | 5 | 1 |
View the last 5 rows of white
:
white.tail()
| fixed acidity | volatile acidity | citric acid | residual sugar | chlorides | free sulfur dioxide | total sulfur dioxide | density | pH | sulphates | alcohol | quality | type | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 4893 | 6.2 | 0.21 | 0.29 | 1.6 | 0.039 | 24.0 | 92.0 | 0.99114 | 3.27 | 0.50 | 11.2 | 6 | 0 |
| 4894 | 6.6 | 0.32 | 0.36 | 8.0 | 0.047 | 57.0 | 168.0 | 0.99490 | 3.15 | 0.46 | 9.6 | 5 | 0 |
| 4895 | 6.5 | 0.24 | 0.19 | 1.2 | 0.041 | 30.0 | 111.0 | 0.99254 | 2.99 | 0.46 | 9.4 | 6 | 0 |
| 4896 | 5.5 | 0.29 | 0.30 | 1.1 | 0.022 | 20.0 | 110.0 | 0.98869 | 3.34 | 0.38 | 12.8 | 7 | 0 |
| 4897 | 6.0 | 0.21 | 0.38 | 0.8 | 0.020 | 22.0 | 98.0 | 0.98941 | 3.26 | 0.32 | 11.8 | 6 | 0 |
Sample 5 rows of red
:
red.sample(5)
| fixed acidity | volatile acidity | citric acid | residual sugar | chlorides | free sulfur dioxide | total sulfur dioxide | density | pH | sulphates | alcohol | quality | type | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1116 | 7.0 | 0.69 | 0.07 | 2.5 | 0.091 | 15.0 | 21.0 | 0.99572 | 3.38 | 0.60 | 11.3 | 6 | 1 |
| 1099 | 8.6 | 0.52 | 0.38 | 1.5 | 0.096 | 5.0 | 18.0 | 0.99666 | 3.20 | 0.52 | 9.4 | 5 | 1 |
| 680 | 13.3 | 0.43 | 0.58 | 1.9 | 0.070 | 15.0 | 40.0 | 1.00040 | 3.06 | 0.49 | 9.0 | 5 | 1 |
| 1123 | 10.7 | 0.40 | 0.37 | 1.9 | 0.081 | 17.0 | 29.0 | 0.99674 | 3.12 | 0.65 | 11.2 | 6 | 1 |
| 1509 | 7.9 | 0.18 | 0.40 | 1.8 | 0.062 | 7.0 | 20.0 | 0.99410 | 3.28 | 0.70 | 11.1 | 5 | 1 |
Summary Statistics
about our data to assess its quality:
# Describe `white`
white.describe()
| fixed acidity | volatile acidity | citric acid | residual sugar | chlorides | free sulfur dioxide | total sulfur dioxide | density | pH | sulphates | alcohol | quality | type | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 4898.000000 | 4898.000000 | 4898.000000 | 4898.000000 | 4898.000000 | 4898.000000 | 4898.000000 | 4898.000000 | 4898.000000 | 4898.000000 | 4898.000000 | 4898.000000 | 4898.0 |
| mean | 6.854788 | 0.278241 | 0.334192 | 6.391415 | 0.045772 | 35.308085 | 138.360657 | 0.994027 | 3.188267 | 0.489847 | 10.514267 | 5.877909 | 0.0 |
| std | 0.843868 | 0.100795 | 0.121020 | 5.072058 | 0.021848 | 17.007137 | 42.498065 | 0.002991 | 0.151001 | 0.114126 | 1.230621 | 0.885639 | 0.0 |
| min | 3.800000 | 0.080000 | 0.000000 | 0.600000 | 0.009000 | 2.000000 | 9.000000 | 0.987110 | 2.720000 | 0.220000 | 8.000000 | 3.000000 | 0.0 |
| 25% | 6.300000 | 0.210000 | 0.270000 | 1.700000 | 0.036000 | 23.000000 | 108.000000 | 0.991723 | 3.090000 | 0.410000 | 9.500000 | 5.000000 | 0.0 |
| 50% | 6.800000 | 0.260000 | 0.320000 | 5.200000 | 0.043000 | 34.000000 | 134.000000 | 0.993740 | 3.180000 | 0.470000 | 10.400000 | 6.000000 | 0.0 |
| 75% | 7.300000 | 0.320000 | 0.390000 | 9.900000 | 0.050000 | 46.000000 | 167.000000 | 0.996100 | 3.280000 | 0.550000 | 11.400000 | 6.000000 | 0.0 |
| max | 14.200000 | 1.100000 | 1.660000 | 65.800000 | 0.346000 | 289.000000 | 440.000000 | 1.038980 | 3.820000 | 1.080000 | 14.200000 | 9.000000 | 0.0 |
It is very important to be aware of differences amongst the variables. We can see that some of the variables have a lot of difference in their min
and max
values.
Double check for null
values:
print("White Wine:")
print(pd.isnull(white).count())
print("\n""Red Wine:")
print(pd.isnull(red).count())
White Wine:
fixed acidity 4898
volatile acidity 4898
citric acid 4898
residual sugar 4898
chlorides 4898
free sulfur dioxide 4898
total sulfur dioxide 4898
density 4898
pH 4898
sulphates 4898
alcohol 4898
quality 4898
dtype: int64
Red Wine:
fixed acidity 1599
volatile acidity 1599
citric acid 1599
residual sugar 1599
chlorides 1599
free sulfur dioxide 1599
total sulfur dioxide 1599
density 1599
pH 1599
sulphates 1599
alcohol 1599
quality 1599
dtype: int64
3.1 Visualizing The Data
Let’s take a look at the distribution of some of the dataset’s variables and make scatter plots to see possible correlations.
Alcohol
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 2)
ax[0].hist(red.alcohol, 10, facecolor='red', alpha=0.5, label="Red wine")
ax[1].hist(white.alcohol, 10, facecolor='white', ec="black", lw=0.5, alpha=0.5, label="White wine")
fig.subplots_adjust(left=0, right=1, bottom=0, top=0.5, hspace=0.05, wspace=1)
ax[0].set_ylim([0, 1000])
ax[0].set_xlabel("Alcohol in % Vol")
ax[0].set_ylabel("Frequency")
ax[1].set_xlabel("Alcohol in % Vol")
ax[1].set_ylabel("Frequency")
#ax[0].legend(loc='best')
#ax[1].legend(loc='best')
fig.suptitle("Distribution of Alcohol in % Vol")
plt.show()
We can see that the alcohol levels between the red and white wine are mostly the same: they have around 9% of alcohol. There are also a considerable amount of observations that have 10% or 11% of alcohol percentage.
# print(np.histogram(red.alcohol, bins=[7,8,9,10,11,12,13,14,15]))
# print(np.histogram(white.alcohol, bins=[7,8,9,10,11,12,13,14,15]))
Sulphates
One thing that we should look at is the relationship between the sulphates
and the quality
of the wine. High levels of sulphate are known to cause headaches and may influence the quality of the wine as well as its rating.
Let’s take a look:
fig, ax = plt.subplots(1, 2, figsize=(8, 4))
ax[0].scatter(red['quality'], red["sulphates"], color="red")
ax[1].scatter(white['quality'], white['sulphates'], color="white", edgecolors="black", lw=0.5)
ax[0].set_title("Red Wine")
ax[1].set_title("White Wine")
ax[0].set_xlabel("Quality")
ax[1].set_xlabel("Quality")
ax[0].set_ylabel("Sulphates")
ax[1].set_ylabel("Sulphates")
ax[0].set_xlim([0,10])
ax[1].set_xlim([0,10])
ax[0].set_ylim([0,2.5])
ax[1].set_ylim([0,2.5])
fig.subplots_adjust(wspace=0.5)
fig.suptitle("Wine Quality by Amount of Sulphates")
plt.show()
Red wine seems to contain more sulphates than white wine, which only has a couple of exceptions that fall just above 1 g/dm3dm3. This could maybe explain why red wine causes headaches.
In regards to the quality, we can clearly see that there is white wine with a relatively low amount of sulphates that gets a score of 9, but for the rest it’s difficult to interpret the data correctly at this point.
We need to take into account that the difference in observations could also affect the graphs and how we might interpret them.
Acidity
Apart from the sulphates, the acidity is one of the major and important wine characteristics that is necessary to achieve quality wines. Great wines often balance out acidity, tannin, alcohol and sweetness. In quantities of 0.2 to 0.4 g/L, volatile acidity doesn’t affect a wine’s quality. At higher levels, however, volatile acidity can give wine a sharp, vinegary tactile sensation. Extreme volatile acidity signifies a seriously flawed wine.
Let’s put the data to the test and make a scatter plot that plots the alcohol versus the volatile acidity. The data points will be colored according to their rating or quality
label:
np.random.seed(570)
redlabels = np.unique(red['quality'])
whitelabels = np.unique(white['quality'])
fig, ax = plt.subplots(1, 2, figsize=(8, 4))
redcolors = np.random.rand(6,4)
whitecolors = np.append(redcolors, np.random.rand(1,4), axis=0)
for i in range(len(redcolors)):
redy = red['alcohol'][red.quality == redlabels[i]]
redx = red['volatile acidity'][red.quality == redlabels[i]]
ax[0].scatter(redx, redy, c=redcolors[i])
for i in range(len(whitecolors)):
whitey = white['alcohol'][white.quality == whitelabels[i]]
whitex = white['volatile acidity'][white.quality == whitelabels[i]]
ax[1].scatter(whitex, whitey, c=whitecolors[i])
ax[0].set_title("Red Wine")
ax[1].set_title("White Wine")
ax[0].set_xlim([0,1.7])
ax[1].set_xlim([0,1.7])
ax[0].set_ylim([5,15.5])
ax[1].set_ylim([5,15.5])
ax[0].set_xlabel("Volatile Acidity")
ax[0].set_ylabel("Alcohol")
ax[1].set_xlabel("Volatile Acidity")
ax[1].set_ylabel("Alcohol")
#ax[0].legend(redlabels, loc='best', bbox_to_anchor=(1.3, 1))
ax[1].legend(whitelabels, loc='best', bbox_to_anchor=(1.3, 1))
#fig.suptitle("Alcohol - Volatile Acidity")
fig.subplots_adjust(top=0.85, wspace=0.7)
plt.show()
The colors in this image are randomly chosen with the help of the numpy random
module. We can always change this by passing a list to the redcolors
or whitecolors
variables.
Keep in mind that the white wine data has one unique quality
value more than the red wine data.
3.2 Data Observation
- Some of the variables of our data sets have values that are considerably far apart
- We have an ideal scenario: there are no null values in the data sets
- Most wines that were included in the data set have around 9% of alcohol
- Red wine seems to contain more sulphates than the white wine, which has less sulphates above 1 g/dm3dm3
- Most wines had a volatile acidity of 0.5 and below. At the moment, there is no direct relation to the quality of the wine
4. Preprocess Data
Let’s preprocess the data so we can start building our neural network.
# Add `type` column to `red` with value 1
red['type'] = 1
# Add `type` column to `white` with value 0
white['type'] = 0
# Append `white` to `red`
wines = red.append(white, ignore_index=True)
We set ignore_index
to True
in this case because we don’t want to keep the index labels of white
when we are appending the data to red
: we want the labels to continue from where they left off in red
, not duplicate index labels from joining both data sets together.
Correlation Matrix
Since it can be somewhat difficult to interpret graphs, it’s also a good idea to plot a correlation matrix. This will give insights more quickly about which variables correlate:
import seaborn as sns
corr = wines.corr()
sns.heatmap(corr,
xticklabels=corr.columns.values,
yticklabels=corr.columns.values)
sns.plt.show()
As we would expect, there are some variables that correlate, such as density
and residual sugar
. Also volatile acidity
and type
are more closely connected than we originally thought.
5. Train and Test Sets
Imbalanced data typically refers to a problem with classification problems where the classes are not represented equally. Most classification data sets do not have exactly equal number of instances in each class, but a small difference often does not matter.
We need to make sure that all two classes of wine are present in the training model. The amount of instances of all two wine types needs to be more or less equal so that we do not favor one class over the other in our predictions.
We can import the train_test_split
from sklearn.model_selection
and assign the data and the target labels to the variables X
and y
. We will see that we need to flatten the array of target labels in order to be completely ready to use the X
and y
variables as input for the train_test_split()
function.
# Import `train_test_split` from `sklearn.model_selection`
from sklearn.model_selection import train_test_split
# Specify the data
X=wines.iloc[:,0:11]
# Specify the target labels and flatten the array
y= np.ravel(wines.type)
# Split the data up in train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
6. Standardize The Data
Some of the values in the white
and red
data sets are far apart and we need to do some standardization to work with these values.
# Import `StandardScaler` from `sklearn.preprocessing`
from sklearn.preprocessing import StandardScaler
# Define the scaler
scaler = StandardScaler().fit(X_train)
# Scale the train set
X_train = scaler.transform(X_train)
# Scale the test set
X_test = scaler.transform(X_test)
7. Model Data
Since we only have two classes, white and red, we are going to do a binary classification. We have already encoded red as 1 and white as 0.
A type of network that performs well on such a problem is a multi-layer perceptron. We are looking to build a fairly simple stack of fully-connected layers to solve our problem and we will use the relu
activation fuction.
A quick way to get started on building our multi-layer perceptron is to use the Keras Sequential model: it’s a linear stack of layers. We can easily create the model by passing a list of layer instances to the constructor, which is set up by running model = Sequential()
.
When making our model, it’s important to take into account that our first layer needs to make the input shape clear. The model needs to know what input shape to expect and that’s why we will always find the input_shape
, input_dim
, input_length
, or batch_size
arguments from the documentation.
In this case, we have to use a Dense
layer, which is a fully connected layer. Dense layers implement the following operation: output = activation(dot(input, kernel) + bias)
. Note that without the activation function, our Dense layer would only consist of two linear operations: a dot product and an addition.
In the first layer, the activation
argument takes the value relu
. Next, we also see that the input_shape
has been defined. This is the input
of the operation that we have just seen: the model takes as input arrays of shape (12,)
, or (*, 12)
. Finally, we can see that the first layer has 12
as a first value for the units
argument of Dense()
, which is the dimensionality of the output space, which are actually 12 hidden units. This means that the model will output arrays of shape (*, 12)
: this is is the dimensionality of the output space.
The units
actually represents the kernel
of the above formula or the weights matrix, composed of all weights given to all input nodes, created by the layer. Note that we don’t include any bias because we haven’t included the use_bias
argument and set it to TRUE
, which is also a possibility.
The intermediate layer also uses the relu
activation function. The output of this layer will be arrays of shape (*,8)
.
We are ending the network with a Dense
layer of size 1. The final layer will also use a sigmoid
activation function so that our output is actually a probability; This means that this will result in a score between 0 and 1, indicating how likely the sample is to have the target “1”, or how likely the wine is to be red.
# Import `Sequential` from `keras.models`
from keras.models import Sequential
# Import `Dense` from `keras.layers`
from keras.layers import Dense
# Initialize the constructor
model = Sequential()
# Add an input layer
model.add(Dense(12, activation='relu', input_shape=(11,)))
# Add one hidden layer
model.add(Dense(8, activation='relu'))
# Add an output layer
model.add(Dense(1, activation='sigmoid'))
Using TensorFlow backend.
We see that there are two key architecture decisions that we need to make to build our model:
- How many layers we are going to use and
- How many “hidden units” we will chose for each layer
In this case, we picked 12
hidden units for the first layer of our model: this is the dimensionality of the output space. We are setting the amount of freedom that we are allowing the network to have when it’s learning representations. If we would allow more hidden units, our network will be able to learn more complex representations but it will also be a more expensive operations that can be prone to overfitting. Overfitting occurs when the model is too complex: it will describe random error or noise and not the underlying relationship that it needs to describe.
# Model output shape
model.output_shape
# Model summary
model.summary()
# Model config
model.get_config()
# List all weight tensors
model.get_weights()
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_1 (Dense) (None, 12) 144
_________________________________________________________________
dense_2 (Dense) (None, 8) 104
_________________________________________________________________
dense_3 (Dense) (None, 1) 9
=================================================================
Total params: 257
Trainable params: 257
Non-trainable params: 0
_________________________________________________________________
[array([[ 0.2896654 , 0.01695609, -0.1637314 , -0.4055706 , -0.1897687 ,
0.05104744, -0.47552979, 0.04375035, 0.14994401, 0.18585712,
0.04605234, 0.4203161 ],
[ 0.09246093, -0.00486219, 0.15394145, -0.3556453 , 0.37075537,
-0.09201503, 0.22433394, 0.49172276, 0.02939814, -0.00528288,
-0.28554958, -0.29101855],
[ 0.13772285, 0.10540932, -0.16185051, -0.13713309, -0.30931568,
0.29137081, 0.22610158, -0.03789827, 0.03900152, -0.13670495,
0.02206749, 0.07224816],
[ 0.12972063, -0.46136355, -0.1358273 , -0.03706533, 0.21573442,
0.21198452, -0.02762926, -0.19320443, 0.24703926, -0.42241281,
0.29690397, -0.07473344],
[-0.06937274, 0.13956004, -0.04767117, 0.03820831, 0.27192348,
-0.47782913, -0.09866273, -0.42932004, -0.04532751, -0.17295876,
-0.34326571, 0.48160571],
[ 0.06270897, 0.10312521, 0.34606183, -0.12457022, -0.16116223,
0.03542614, 0.15460205, -0.48483256, -0.21644399, 0.17074299,
-0.31874129, -0.00338858],
[-0.12783119, -0.04838416, 0.20839161, 0.33239806, 0.10142457,
-0.30532336, -0.38364607, 0.38588023, 0.01854885, 0.05628592,
0.19293177, -0.05149972],
[-0.43119535, -0.27155614, -0.46491459, -0.25988257, 0.09503597,
-0.5009988 , -0.15289614, -0.41986507, 0.49207467, 0.00157392,
-0.16561732, 0.24532884],
[-0.17463535, 0.08331698, 0.27836359, -0.14132953, -0.30007723,
-0.32280877, -0.1596224 , 0.32339281, -0.29511583, 0.41530758,
-0.45230752, -0.4677496 ],
[ 0.00880128, 0.33655512, -0.45286989, 0.43754292, -0.04207084,
-0.3803001 , 0.21270508, 0.43465519, 0.46255559, -0.18048412,
-0.29980046, 0.45833129],
[-0.31532359, -0.26553845, -0.21347395, -0.48159593, 0.50684947,
0.29534268, 0.16204995, 0.30744392, 0.02605116, -0.42019787,
-0.2871666 , 0.01862645]], dtype=float32),
array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32),
array([[ 0.13802433, -0.1397422 , 0.37863284, -0.15413004, 0.52855718,
-0.13628149, 0.03936303, -0.25822985],
[-0.49231729, -0.38898361, -0.35550442, -0.08421832, -0.25332853,
-0.01050067, 0.28014278, 0.45117211],
[ 0.12644804, -0.07388979, 0.54314303, 0.32438159, 0.36960304,
0.03181666, -0.4164722 , -0.5394448 ],
[ 0.4500739 , 0.19391423, -0.21727106, -0.30200374, -0.48891065,
0.42746753, -0.34170333, -0.21399096],
[-0.53348607, -0.34708104, -0.44702923, 0.31050652, -0.52960402,
0.4368825 , -0.46614015, 0.21192652],
[-0.50510532, 0.35415596, -0.37515181, -0.2976757 , -0.45574439,
-0.53875005, 0.50481069, 0.12087846],
[ 0.49851513, -0.30494523, 0.10521847, -0.46860957, 0.2679804 ,
-0.04077768, -0.00542253, 0.31112713],
[-0.34450638, -0.16991124, -0.38176683, -0.38524371, -0.49763155,
0.37959671, 0.42052734, 0.38327682],
[-0.36905417, 0.40031129, -0.1917389 , 0.21109205, 0.33099413,
0.1206221 , -0.02995032, -0.21631998],
[ 0.0382123 , 0.51903856, 0.31960887, -0.01158792, -0.05701348,
0.49415326, -0.36317486, -0.18171829],
[ 0.42716026, 0.4860462 , 0.29231024, -0.49826044, 0.38350588,
0.51668561, -0.35148156, 0.00427073],
[ 0.14594537, -0.22531378, 0.36939985, -0.14032108, -0.48043332,
-0.00821644, 0.54728377, -0.17121464]], dtype=float32),
array([ 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32),
array([[ 0.76886392],
[ 0.16227716],
[ 0.38850141],
[-0.30456817],
[ 0.39023936],
[-0.56345725],
[-0.12128478],
[ 0.20257616]], dtype=float32),
array([ 0.], dtype=float32)]
8. Compile and Fit
Now we need to compile our model and fit it to the data.
model.compile(loss='binary_crossentropy',
optimizer='adam',
metrics=['accuracy'])
model.fit(X_train, y_train,epochs=20, batch_size=1, verbose=1)
Epoch 1/20
4352/4352 [==============================] - 14s - loss: 0.0901 - acc: 0.9692
Epoch 2/20
4352/4352 [==============================] - 16s - loss: 0.0221 - acc: 0.9959
Epoch 3/20
4352/4352 [==============================] - 15s - loss: 0.0195 - acc: 0.9966
Epoch 4/20
4352/4352 [==============================] - 14s - loss: 0.0166 - acc: 0.9972
Epoch 5/20
4352/4352 [==============================] - 15s - loss: 0.0152 - acc: 0.9975
Epoch 6/20
4352/4352 [==============================] - 15s - loss: 0.0141 - acc: 0.9972
Epoch 7/20
4352/4352 [==============================] - 15s - loss: 0.0133 - acc: 0.9972
Epoch 8/20
4352/4352 [==============================] - 16s - loss: 0.0152 - acc: 0.9972
Epoch 9/20
4352/4352 [==============================] - 14s - loss: 0.0116 - acc: 0.9977
Epoch 10/20
4352/4352 [==============================] - 15s - loss: 0.0110 - acc: 0.9977
Epoch 11/20
4352/4352 [==============================] - 15s - loss: 0.0113 - acc: 0.9977
Epoch 12/20
4352/4352 [==============================] - 15s - loss: 0.0110 - acc: 0.9975
Epoch 13/20
4352/4352 [==============================] - 15s - loss: 0.0102 - acc: 0.9979
Epoch 14/20
4352/4352 [==============================] - 15s - loss: 0.0098 - acc: 0.9982
Epoch 15/20
4352/4352 [==============================] - 14s - loss: 0.0106 - acc: 0.9979
Epoch 16/20
4352/4352 [==============================] - 14s - loss: 0.0108 - acc: 0.9977
Epoch 17/20
4352/4352 [==============================] - 16s - loss: 0.0094 - acc: 0.9979
Epoch 18/20
4352/4352 [==============================] - 15s - loss: 0.0096 - acc: 0.9979
Epoch 19/20
4352/4352 [==============================] - 15s - loss: 0.0100 - acc: 0.9979
Epoch 20/20
4352/4352 [==============================] - 15s - loss: 0.0082 - acc: 0.9984
<keras.callbacks.History at 0x127d38cc0>
By compiling, we are configure the model with the adam
optimizer and the binary_crossentropy
loss function. Additionally, we can also monitor the accuracy during the training by passing ['accuracy']
to the metrics
argument.
The optimizer
and the loss
are two arguments that are required if we want to compile the model. Some of the most popular optimization algorithms used are the Stochastic Gradient Descent (SGD), ADAM and RMSprop. Depending on whichever algorithm we choose, we will need to tune certain parameters, such as learning rate or momentum. The choice for a loss function depends on the problem we are trying to solve.
We will train the model for 20 epochs or iterations over all the samples in X_train
and y_train
, in batches of 1 sample. By setting the verbose
argument to 1
, we are indicate that we want to see the progress bar logging.
An epoch is a single pass through the entire training set, followed by testing of the verification set. The batch size that we specify in the code above defines the number of samples that going to be propagated through the network. Also, by doing this, we optimize the efficiency because we are making sure that we don’t load too many input patterns into memory at the same time.
9. Predict Values
We can make predictions for the labels of the test set by using predict()
and passing the test set to it. In this case, the result is stored in y_pred
:
y_pred = model.predict(X_test)
Before we go and evaluate our model, we can already get a quick idea of the accuracy by checking how y_pred
and y_test
compare:
print("y_pred:")
print(y_pred[:5])
print("\n""y_test:")
print(y_test[:5])
y_pred:
[[ 1.23926289e-02]
[ 8.67547810e-01]
[ 2.65277573e-04]
[ 1.73703957e-05]
[ 1.84766762e-07]]
y_test:
[0 1 0 0 0]
10. Evaluate Model
We will use evaluate()
and pass in the test data and test labels to evaluate our model’s performance.
score = model.evaluate(X_test, y_test,verbose=1)
print(score)
1504/2145 [====================>.........] - ETA: 0s[0.027259037624980813, 0.99487179487179489]
The score is a list that holds the combination of the loss and the accuracy. In this case, we see that both seem very great, but we also need to remember that our data is somewhat imbalanced, we had more white wine than red wine observations. The accuracy might just be reflecting the class distribution of our data because it will just predict white
because those observations are abundantly present.
Before we start re-arranging the data and putting it together in different ways, it’s always a good idea to try out different evaluation metrics. For this, we will test out some basic classification evaluation techniques, such as:
- The
confusion matrix
, which is a breakdown of predictions into a table showing correct predictions and the types of incorrect predictions made. Ideally, we will only see numbers in the diagonal, which means that all our predictions were correct. Precision
is a measure of a classifier’s exactness. The higher the precision, the more accurate the classifier.Recall
is a measure of a classifier’s completeness. The higher the recall, the more cases the classifier covers.- The
F1 Score
orF-score
is a weighted average of precision and recall. - The
Kappa
orCohen’s kappa
is the classification accuracy normalized by the imbalance of the classes in the data.
# Import the modules from `sklearn.metrics`
from sklearn.metrics import confusion_matrix, precision_score, recall_score, f1_score, cohen_kappa_score
# Confusion matrix
print("Confusion Matrix:")
print(confusion_matrix(y_test, y_pred))
array([[1585, 3], [ 8, 549]])
# Precision
print("\n""Precision:")
print(precision_score(y_test, y_pred))
0.994565217391
# Recall
print("\n""Recall:")
print(recall_score(y_test, y_pred))
0.98563734290843807
# F1 score
print("\n""F1 Score:")
print(f1_score(y_test,y_pred))
0.99008115419296661
# Cohen's kappa
print("\n""Cohen's Kappa:")
print(cohen_kappa_score(y_test, y_pred))
0.98662321692498967
All of our scores are very good, we have made a pretty accurate model despite the fact that we have considerably more rows that are of the white wine type.
11. Further Modeling
We have successfully built our first model, but we can go even further with experimenting. The two key architectural decisions that we need to make involve the layers and the hidden nodes. We can start by testing the following:
- Try to use 2 or 3 hidden layers
- Use layers with more hidden units or less hidden units
- Take the quality column as the target labels and the rest of the data including the encoded type column as our data. Which leaves us with a multi-class classification problem to solve.
- Try changing out the activation function by using the
tanh
activation function instead ofrelu
.
12. Predicting Wine Quality
** Lets build a neural networks to predict wine quality based on its chemical properties.**
Here we assume that quality
is a continuous variable: the task is then not a binary classification
task but an ordinal regression
task. Ordinal Regression is a type of regression that is used for predicting an ordinal variable: the quality
value exists on an arbitrary scale where the relative ordering between the different quality
values is significant. The quality scale 0-10 for “very bad” to “very good” is an example.
Our target labels are going to be the quality
column in our red
and white
DataFrames and will require some additional preprocessing.
12.1 Preprocess Data
Since the quality
variable becomes our target class, we will now need to isolate the quality labels from the rest of the data set. We will put wines.quality
in a different variable y
and will put the rest of the wine data in a variable x
.
We will use StandardScaler
to make sure that our data is in a good place before we fit the data to the model.
Then we will split the data into train and test sets by utilizing k-fold
validation, which requires us to split up the data into K
partitions. Usually, K
is set at 4 or 5. Finally, we can instantiate identical models and train each one on a partition, while also evaluating on the remaining partitions. The validation score for the model is then an average of the K
validation scores obtained.
# Isolate target labels
y = wines.quality
# Isolate data
X = wines.drop('quality', axis=1)
We also need to perform the scaling again because we had a lot of differences in some of the values for our red
, white
data.
# Scale the data with `StandardScaler`
X = StandardScaler().fit_transform(X)
Time to start modeling our neural network.
12.2 Model Neural Network Architecture
Our first layer is our input layer and we will need to pass the shape of our input data to it. We will make use of input_dim
to pass the dimensions of the input data to the Dense
layer.
# Import `Sequential` from `keras.models`
from keras.models import Sequential
# Import `Dense` from `keras.layers`
from keras.layers import Dense
# Initialize the model
model = Sequential()
# Add input layer
model.add(Dense(64, input_dim=12, activation='relu'))
# Add output layer
model.add(Dense(1))
Our input layer needs to know the input dimension of the data, so we will pass in the input dimensions, which is 12. We also need to remember that we are counting the Type
columns that were generated in our first model.
We will use the relu
activation function, with no bias involved, and the number of hidden units will be 64
.
Our network ends with a single unit Dense(1)
, and doesn’t include an activation. This is a typical setup for scalar regression
, where we are trying to predict a single continuous value.
12.3 Compile The Model, Fit The Data
With our model at hand, we can now compile and fit the data to it with the K
fold validation partitions:
import numpy as np
from sklearn.model_selection import StratifiedKFold
seed = 7
np.random.seed(seed)
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
for train, test in kfold.split(X, y):
model = Sequential()
model.add(Dense(64, input_dim=12, activation='relu'))
model.add(Dense(1))
model.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])
model.fit(X[train], y[train], epochs=10, verbose=1)
Epoch 1/10
5195/5195 [==============================] - 0s - loss: 14.2885 - mean_absolute_error: 3.3583
Epoch 2/10
5195/5195 [==============================] - 0s - loss: 1.6251 - mean_absolute_error: 0.9938
Epoch 3/10
5195/5195 [==============================] - 0s - loss: 1.0007 - mean_absolute_error: 0.7737
Epoch 4/10
5195/5195 [==============================] - 0s - loss: 0.7484 - mean_absolute_error: 0.6665
Epoch 5/10
5195/5195 [==============================] - 0s - loss: 0.6334 - mean_absolute_error: 0.6156
Epoch 6/10
5195/5195 [==============================] - 0s - loss: 0.5716 - mean_absolute_error: 0.5859
Epoch 7/10
5195/5195 [==============================] - 0s - loss: 0.5392 - mean_absolute_error: 0.5709
Epoch 8/10
5195/5195 [==============================] - 0s - loss: 0.5210 - mean_absolute_error: 0.5611
Epoch 9/10
5195/5195 [==============================] - 0s - loss: 0.5098 - mean_absolute_error: 0.5565
Epoch 10/10
5195/5195 [==============================] - 0s - loss: 0.5004 - mean_absolute_error: 0.5520 - ETA: 0s - loss: 0.4703 - mean_absolute_error: 0.
Epoch 1/10
5197/5197 [==============================] - 0s - loss: 12.4811 - mean_absolute_error: 3.0996
Epoch 2/10
5197/5197 [==============================] - 0s - loss: 1.4883 - mean_absolute_error: 0.9524
Epoch 3/10
5197/5197 [==============================] - 0s - loss: 0.9228 - mean_absolute_error: 0.7451
Epoch 4/10
5197/5197 [==============================] - 0s - loss: 0.7208 - mean_absolute_error: 0.6578
Epoch 5/10
5197/5197 [==============================] - 0s - loss: 0.6226 - mean_absolute_error: 0.6112
Epoch 6/10
5197/5197 [==============================] - 0s - loss: 0.5700 - mean_absolute_error: 0.5861
Epoch 7/10
5197/5197 [==============================] - 0s - loss: 0.5395 - mean_absolute_error: 0.5695
Epoch 8/10
5197/5197 [==============================] - 0s - loss: 0.5199 - mean_absolute_error: 0.5597
Epoch 9/10
5197/5197 [==============================] - 0s - loss: 0.5092 - mean_absolute_error: 0.5533
Epoch 10/10
5197/5197 [==============================] - 0s - loss: 0.4996 - mean_absolute_error: 0.5487
Epoch 1/10
5197/5197 [==============================] - 0s - loss: 13.3672 - mean_absolute_error: 3.2182
Epoch 2/10
5197/5197 [==============================] - 0s - loss: 1.5880 - mean_absolute_error: 0.9708
Epoch 3/10
5197/5197 [==============================] - 0s - loss: 0.9822 - mean_absolute_error: 0.7553
Epoch 4/10
5197/5197 [==============================] - 0s - loss: 0.7341 - mean_absolute_error: 0.6579
Epoch 5/10
5197/5197 [==============================] - 0s - loss: 0.6144 - mean_absolute_error: 0.6033
Epoch 6/10
5197/5197 [==============================] - 0s - loss: 0.5527 - mean_absolute_error: 0.5755
Epoch 7/10
5197/5197 [==============================] - 0s - loss: 0.5230 - mean_absolute_error: 0.5603
Epoch 8/10
5197/5197 [==============================] - 0s - loss: 0.5081 - mean_absolute_error: 0.5551
Epoch 9/10
5197/5197 [==============================] - 0s - loss: 0.4966 - mean_absolute_error: 0.5446
Epoch 10/10
5197/5197 [==============================] - 0s - loss: 0.4881 - mean_absolute_error: 0.5421
Epoch 1/10
5199/5199 [==============================] - 0s - loss: 12.9529 - mean_absolute_error: 3.1443
Epoch 2/10
5199/5199 [==============================] - 0s - loss: 1.5940 - mean_absolute_error: 0.9716
Epoch 3/10
5199/5199 [==============================] - 0s - loss: 1.0038 - mean_absolute_error: 0.7739 - ETA: 0s - loss: 1.0516 - mean_absolute_error: 0.
Epoch 4/10
5199/5199 [==============================] - 0s - loss: 0.7599 - mean_absolute_error: 0.6665
Epoch 5/10
5199/5199 [==============================] - 0s - loss: 0.6336 - mean_absolute_error: 0.6078
Epoch 6/10
5199/5199 [==============================] - 0s - loss: 0.5754 - mean_absolute_error: 0.5806
Epoch 7/10
5199/5199 [==============================] - 0s - loss: 0.5403 - mean_absolute_error: 0.5648
Epoch 8/10
5199/5199 [==============================] - 0s - loss: 0.5177 - mean_absolute_error: 0.5536
Epoch 9/10
5199/5199 [==============================] - 0s - loss: 0.5049 - mean_absolute_error: 0.5502
Epoch 10/10
5199/5199 [==============================] - 0s - loss: 0.4943 - mean_absolute_error: 0.5436
Epoch 1/10
5200/5200 [==============================] - 0s - loss: 11.7594 - mean_absolute_error: 2.9585
Epoch 2/10
5200/5200 [==============================] - 0s - loss: 1.6008 - mean_absolute_error: 0.9801
Epoch 3/10
5200/5200 [==============================] - 0s - loss: 1.0165 - mean_absolute_error: 0.7773
Epoch 4/10
5200/5200 [==============================] - 0s - loss: 0.7624 - mean_absolute_error: 0.6708
Epoch 5/10
5200/5200 [==============================] - 0s - loss: 0.6438 - mean_absolute_error: 0.6162
Epoch 6/10
5200/5200 [==============================] - 0s - loss: 0.5871 - mean_absolute_error: 0.5885
Epoch 7/10
5200/5200 [==============================] - 0s - loss: 0.5504 - mean_absolute_error: 0.5729
Epoch 8/10
5200/5200 [==============================] - 0s - loss: 0.5221 - mean_absolute_error: 0.5578
Epoch 9/10
5200/5200 [==============================] - 0s - loss: 0.5104 - mean_absolute_error: 0.5518
Epoch 10/10
5200/5200 [==============================] - 0s - loss: 0.4994 - mean_absolute_error: 0.5460
We use the compile()
function to compile the model and then the fit()
function to fit the model to the data. When we compile the model we need to make sure that we define at minimum the optimizer
and loss
arguments. We then pass rsmprop
to our optimizer, and mse
to the loss function.
The additional metrics
argument that we define is actually a function that is used to judge the performance of our model. For regression problems, it’s very common to take the Mean Absolute Error (MAE)
as a metric. Finally, we determine how many epochs we want to run the fitting.
12.4 Evaluate Model
We can evaluate our model by making use of the Mean Squared Error (MSE)
and the Mean Absolute Error (MAE)
.
mse_value, mae_value = model.evaluate(X[test], y[test], verbose=0)
print("Mean Squared Error:")
print(mse_value)
print("\n""Mean Absolute Error:")
print(mae_value)
Mean Squared Error:
0.521800081686
Mean Absolute Error:
0.561619131769
Note that besides the MSE
and MAE
scores, we could also use the R2 score
or the regression score
function.
from sklearn.metrics import r2_score
r2_score(y[test], y_pred)
0.3125092543
Our model didn’t perform has well as we hoped, so we are going to experiment with optimizing the code so that the results become a little bit better.
12.5 Model Fine-Tuning
Most of the time we will need to fine-tune our model because not all problems are as straightforward as we would like them to be.
seed = 7
np.random.seed(seed)
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
for train, test in kfold.split(X, y):
model = Sequential()
model.add(Dense(64, input_dim=12, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dense(1))
model.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])
model.fit(X[train], y[train], epochs=10, verbose=1)
Hidden Units
We can try adding more hidden units to our model’s architecture and study the effect on the evaluation:
seed = 7
np.random.seed(seed)
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
for train, test in kfold.split(X, y):
model = Sequential()
model.add(Dense(128, input_dim=12, activation='relu'))
model.add(Dense(1))
model.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])
model.fit(X[train], y[train], epochs=10, verbose=1)
Something to keep in mind is that, because we don’t have a ton of data, we are more prone to overfitting. That’s why we should work with a small network.
13. More Experiments: Optimization Parameters
Besides adding layers and playing around with the hidden units, we can also try to adjust some of the parameters of the optimization algorithm that we give to the compile()
function. We can try, for example, importing RMSprop
from keras.models
and adjust the learning rate lr
:
from keras.optimizers import RMSprop
seed = 7
np.random.seed(seed)
rmsprop = RMSprop(lr=0.0001)
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
for train, test in kfold.split(X, y):
model = Sequential()
model.add(Dense(12, input_dim=12, activation='relu'))
model.add(Dense(1))
model.compile(optimizer=rmsprop, loss='mse', metrics=['mae'])
model.fit(X[train], y[train], epochs=10, verbose=1)
Using the Stochastic Gradient Descent (SGD) optimization algorithm:
from keras.optimizers import SGD, RMSprop
seed = 7
np.random.seed(seed)
sgd=SGD(lr=0.1)
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
for train, test in kfold.split(X, y):
model = Sequential()
model.add(Dense(12, input_dim=12, activation='relu'))
model.add(Dense(1))
model.compile(optimizer=sgd, loss='mse', metrics=['mae'])
model.fit(X[train], y[train], epochs=10, verbose=1)


Type a letter in the input field:
{{lvl1.text}}
{{lvl2.text}}
The list will only consists of names matching the filter.


#KCPE2019 Results Set To Be Released Today
by WycliffeThe Kenya National Examinations Council (KNEC) is set to release the Kenya Certificate of Primary Education (KCPE) results today.
A source intimated to Kahawa Tungu that Education Cabinet Secretary George Magoha is set to brief President Uhuru Kenyatta on this year’s KCPE report before releasing the results on Monday afternoon.
KNEC officials have also gathered at KNEC headquarters ahead of the release.
This comes 18 days after the examinations came to an end.
The Education ministry has been releasing the results earlier than in previous years for the past three years.
Marking of the exams ended last week and was largely aided by the Optical Mark Recognition (OMR) machines except for English Composition and Kiswahili Insha papers.
1,088,986 candidates sat for the exams this year.


>
An explanation of the concepts in the system, including a guide to writing your own grammars.
A full listing and description of the public API exported by the library.
The version history of the project, listing all releases and the changes they made.
A discussion board for asking questions and giving feedback.