Q:

How to time-efficiently remove values next to 'NaN' values?

I'm trying to remove wrong values form my data (a series of 15mln values, 700MB). The values to be removed are values next to 'nan' values, e.g.:
Series: /1/,nan,/2/,3,/4/,nan,nan,nan,/8/,9
Numbers surrounded by slashes i.e. /1/,/2/,/4/,/8/ are values, which should be removed.
The problem is that it takes way too long to compute that with the following code that I have: 
%%time

import numpy as np
import pandas as pd

# sample data
speed = np.random.uniform(0,25,15000000)
next_speed = speed[1:]

# create a dataframe
data_dict = {'speed': speed[:-1],
            'next_speed': next_speed}

df = pd.DataFrame(data_dict)

# calculate difference between the current speed and the next speed
list_of_differences = []

for i in df.index:
    difference = df.next_speed[i]-df.speed[i]
    list_of_differences.append(difference)

df['difference'] = list_of_differences

# add 'nan' to data in form of a string. 

for i in range(len(df.difference)):
    # arbitrary condition
    if df.difference[i] < -2:
        df.difference[i] = 'nan'

#########################################
# THE TIME-INEFFICIENT LOOP

# remove wrong values before and after 'nan'.
for i in  range(len(df)):

    # check if the value is a number to skip computations of the following "if" cases
    if not(isinstance(df.difference[i], str)):
        continue

    # case 1: where there's only one 'nan' surrounded by values. 
    # Without this case the algo will miss some wrong values because 'nan' will be removed
    # Example of a series: /1/,nan,/2/,3,4,nan,nan,nan,8,9
    # A number surrounded by slashes e.g. /1/ is a value to be removed
    if df.difference[i] == 'nan' and df.difference[i-1] != 'nan' and df.difference[i+1] != 'nan':
        df.difference[i-1]= 'wrong'
        df.difference[i+1]= 'wrong'

    # case 2: where the following values are 'nan': /1/, nan, nan, 4
    # E.g.: /1/, nan,/2/,3,/4/,nan,nan,nan,8,9
    elif df.difference[i] == 'nan' and df.difference[i+1] == 'nan':
        df.difference[i-1]= 'wrong'

    # case 3: where next value is NOT 'nan'  wrong, nan,nan,4 
        # E.g.: /1/, nan,/2/,3,/4/,nan,nan,nan,/8/,9
    elif df.difference[i] == 'nan' and df.difference[i+1] != 'nan':
        df.difference[i+1]= 'wrong'

How to make it more time-efficient?

A:

This is still a work in progress for me. I knocked 100x off your dummy data size to get down to something I could stand to wait for.
I also added this code at the top of my version:
 import time

current_milli_time = lambda: int(round(time.time() * 1000))

def mark(s):
    print("[{}] {}".format(current_milli_time()/1000, s))

This just prints a string with a time-mark in front of it, to see what's taking so long.
With that done, in your 'difference' column computation, you can replace the manual list generation with a vector operation. This code:
df = pd.DataFrame(data_dict)

mark("Got DataFrame")

# calculate difference between the current speed and the next speed
list_of_differences = []

for i in df.index:
    difference = df.next_speed[i]-df.speed[i]
    list_of_differences.append(difference)

df['difference'] = list_of_differences
mark("difference 1")

df['difference2'] = df['next_speed'] - df['speed']
mark('difference 2')

print(df[:10])

Produces this output:
[1490943913.921] Got DataFrame
[1490943922.094] difference 1
[1490943922.096] difference 2
   next_speed      speed  difference  difference2
0   18.008314  20.182982   -2.174669    -2.174669
1   14.736095  18.008314   -3.272219    -3.272219
2    5.352993  14.736095   -9.383102    -9.383102
3    5.854199   5.352993    0.501206     0.501206
4    2.003826   5.854199   -3.850373    -3.850373
5   12.736061   2.003826   10.732236    10.732236
6    2.512623  12.736061  -10.223438   -10.223438
7   18.224716   2.512623   15.712093    15.712093
8   14.023848  18.224716   -4.200868    -4.200868
9   15.991590  14.023848    1.967741     1.967741

Notice that the two difference columns are the same, but the second version took about 8 seconds less time. (Presumably 800 seconds when you have 100x more data.)
I did the same thing in the 'nanify' process:
df.difference2[df.difference2 < -2] = np.nan

The idea here is that many of the binary operators actually generate either a placeholder, or a Series or vector. And that can be used as an index, so that df.difference2 < -2 becomes (in essence) a list of the places where that condition is true, and you can then index either df (the whole table) or any of the columns of df, like df.difference2, using that index. It's a fast shorthand for the otherwise-slow python for loop.
Update
Okay, finally, here is a version that vectorizes the "Time-inefficient Loop". I'm just pasting the whole thing in at the bottom, for copying.
The premise is that the Series.isnull() method returns a boolean Series (column) that is true if the contents are "missing" or "invalid" or "bogus." Generally, this means NaN, but it also recognizes Python None, etc.
The tricky part, in pandas, is shifting that column up or down by one to reflect "around"-ness. 
That is, I want another boolean column, where col[n-1] is true if col[n] is null. That's my "before a nan" column. And likewise, I want another column where col[n+1] is true if col[n] is null. That's my "after a nan" column.
It turns out I had to take the damn thing apart! I had to reach in, extract the underlying numpy array using the Series.values attribute, so that the pandas index would be discarded. Then a new index is created, starting at 0, and everything works again. (If you don't strip the index, the columns "remember" what their numbers are supposed to be. So even if you delete column[0], the column doesn't shift down. Instead, is knows "I am missing my [0] value, but everyone else is still in the right place!")
Anyway, with that figured out, I was able to build three columns (needlessly - they could probably be parts of an expression) and then merge them together into a fourth column that indicates what you want: the column is True when the row is before, on, or after a nan value.
missing = df.difference2.isnull()
df['is_nan'] = missing
df['before_nan'] = np.append(missing[1:].values, False)
df['after_nan'] = np.insert(missing[:-1].values, 0, False)
df['around_nan'] = df.is_nan | df.before_nan | df.after_nan

Here's the whole thing:
import numpy as np
import pandas as pd

import time

current_milli_time = lambda: int(round(time.time() * 1000))

def mark(s):
    print("[{}] {}".format(current_milli_time()/1000, s))

# sample data
speed = np.random.uniform(0,25,150000)
next_speed = speed[1:]

# create a dataframe
data_dict = {'speed': speed[:-1],
            'next_speed': next_speed}

df = pd.DataFrame(data_dict)

mark("Got DataFrame")

# calculate difference between the current speed and the next speed
list_of_differences = []

#for i in df.index:
    #difference = df.next_speed[i]-df.speed[i]
    #list_of_differences.append(difference)

#df['difference'] = list_of_differences
#mark("difference 1")

df['difference'] = df['next_speed'] - df['speed']
mark('difference 2')

df['difference2'] = df['next_speed'] - df['speed']

# add 'nan' to data in form of a string.

#for i in range(len(df.difference)):
    ## arbitrary condition
    #if df.difference[i] < -2:
        #df.difference[i] = 'nan'

df.difference[df.difference < -2] = np.nan
mark('nanify')

df.difference2[df.difference2 < -2] = np.nan
mark('nanify 2')

missing = df.difference2.isnull()
df['is_nan'] = missing
df['before_nan'] = np.append(missing[1:].values, False)
df['after_nan'] = np.insert(missing[:-1].values, 0, False)
df['around_nan'] = df.is_nan | df.before_nan | df.after_nan
mark('looped')

#########################################
# THE TIME-INEFFICIENT LOOP

# remove wrong values before and after 'nan'.
for i in  range(len(df)):

    # check if the value is a number to skip computations of the following "if" cases
    if not(isinstance(df.difference[i], str)):
        continue

    # case 1: where there's only one 'nan' surrounded by values.
    # Without this case the algo will miss some wrong values because 'nan' will be removed
    # Example of a series: /1/,nan,/2/,3,4,nan,nan,nan,8,9
    # A number surrounded by slashes e.g. /1/ is a value to be removed
    if df.difference[i] == 'nan' and df.difference[i-1] != 'nan' and df.difference[i+1] != 'nan':
        df.difference[i-1]= 'wrong'
        df.difference[i+1]= 'wrong'

    # case 2: where the following values are 'nan': /1/, nan, nan, 4
    # E.g.: /1/, nan,/2/,3,/4/,nan,nan,nan,8,9
    elif df.difference[i] == 'nan' and df.difference[i+1] == 'nan':
        df.difference[i-1]= 'wrong'

    # case 3: where next value is NOT 'nan'  wrong, nan,nan,4
        # E.g.: /1/, nan,/2/,3,/4/,nan,nan,nan,/8/,9
    elif df.difference[i] == 'nan' and df.difference[i+1] != 'nan':
        df.difference[i+1]= 'wrong'

mark('time-inefficient loop done')

