Reputation: 1024
I have a list in python like this [4, 0, 0, 6, 0, 8, 0, 0, 0, 3]
, and I want to convert into something like this [4, 4.67, 5.33, 6, 7, 8, 6.75, 5.5, 4.25, 3]
. Basically just replacing zeroes with an interpolation of the points already in the list. Any ideas?
Upvotes: 0
Views: 2322
Reputation: 42133
Using accumulate from itertools, you can find the starting and ending indexes for streaks of zeros around each position. Then use these ranges to compute a linear ratio for each zero position relative to its starting and ending non-zero range boundaries:
from itertools import accumulate
n = [4, 0, 0, 6, 0, 8, 0, 0, 0, 3]
starts = accumulate(range(len(n)),lambda a,b: b if n[b] else a)
ends = [*accumulate(reversed(range(len(n))),lambda a,b: b if n[b] else a)][::-1]
inter = [ n[i] or n[s]+(n[e]-n[s])*(i-s)/(e-s) for i,(s,e) in enumerate(zip(starts,ends)) ]
# inter = [4, 4.666666666666667, 5.333333333333333, 6, 7.0, 8, 6.75, 5.5, 4.25, 3]
The starts
list will contain the index of the previous non-zero value for each position (uses the position itself for non-zero values):
[0, 0, 0, 3, 3, 5, 5, 5, 5, 9]
The ends
list contains the index of the next non-zero values
[0, 3, 3, 3, 5, 5, 9, 9, 9, 9]
Combining these two lists using zip we obtain all the information needed to compute the intermediate values:
start end range position Interpolation
index value start end value value size in range ratio value
(i) n[i] (s) (e) n[s] n[e] e-s i-s (i-s)/(e-s) see below
0 4 0 0 4 4 0 0 ----- 4
1 0 0 3 4 6 3 1 0.67 4.67
2 0 0 3 4 6 3 2 0.33 5.33
3 6 3 3 6 6 0 0 ----- 6
4 0 3 5 6 8 2 1 0.50 7.00
5 8 5 5 8 8 0 0 ----- 8
6 0 5 9 8 3 4 1 0.75 6.75
7 0 5 9 8 3 4 2 0.50 5.50
8 0 5 9 8 3 4 3 0.25 4.25
9 3 9 9 3 3 0 0 ----- 3
Keeping non-zero values where present and calculating the interpolated value as startValue + (endValue-startValue) x InterpolationRatio
for zero positions.
Upvotes: 0
Reputation: 29742
One way using pandas.Series.interpolate
:
import pandas as pd
pd.Series([i if i else np.nan for i in l]).interpolate().tolist()
Output:
[4.0,
4.666666666666667,
5.333333333333333,
6.0,
7.0,
8.0,
6.75,
5.5,
4.25,
3.0]
Upvotes: 2