Python 找到一组值=列表中的0
我正在寻找一种在python列表中查找“平台”或组的简单方法。作为输入,我有如下内容:Python 找到一组值=列表中的0,python,numpy,Python,Numpy,我正在寻找一种在python列表中查找“平台”或组的简单方法。作为输入,我有如下内容: mydata = [0.0, 0.0, 0.0, 0.0, 0.0, 0.143, 0.0, 0.22, 0.135, 0.44, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.33, 0.65, 0.22, 0.0, 0.0, 0.0, 0.0, 0.0] 我想提取每个“组”的中间位置。在本例中,组定义为以下数据:=0,例如至少3个位置。应忽略包围的单零(如
mydata = [0.0, 0.0, 0.0, 0.0, 0.0, 0.143, 0.0, 0.22, 0.135, 0.44, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.33, 0.65, 0.22, 0.0, 0.0, 0.0, 0.0, 0.0]
我想提取每个“组”的中间位置。在本例中,组定义为以下数据:=0,例如至少3个位置。应忽略包围的单零(如位置6)
基本上,我希望得到以下输出:
myoutput = [8, 20]
对于我的用例来说,获得非常精确的输出数据并不重要<代码>[10,21]仍然可以
总结:第一组:[0.143,0.0,0.22,0.135,0.44,0.1]
;第二组:[0.33,0.65,0.22]
。现在是中间元素的位置(如果没有真正的中间值,则从中间向左或向右)。因此,在输出中,8
将是第一组的中间位置,20
将是第二组的中间位置
我已经试过一些方法了。但它们并不像我希望的那样稳定(例如:更多的封闭零可能导致问题)。因此,在投入更多时间研究这个想法之前,我想问一下是否有更好的方法来实现这个特性。我甚至认为这可能是一个普遍的问题。可能已经有标准代码来解决这个问题了吗
有一些方法描述了大致相同的问题,但我也需要在处理之前“平滑”数据
1.)平滑数据-去除包围的零
import numpy as np
def smooth(y, box_pts):
box = np.ones(box_pts)/box_pts
y_smooth = np.convolve(y, box, mode='same')
return y_smooth
y_smooth = smooth(mydata, 20)
2.)在平滑列表中查找起始点(如果值为!=0且之前的值为0,则应为起始点)。如果找到端点:使用找到的最后一个起始点和当前端点获取组的中间位置,并将其写入deque
laststart = 0
lastend = 0
myoutput = deque()
for i in range(1, len(y_smooth)-1):
#detect start:
if y_smooth[i]!=0 and y_smooth[i-1]==0:
laststart = i
#detect end:
elif y_smooth[i]!=0 and y_smooth[i+1]==0 and laststart+2 < i:
lastend = i
myoutput.appendleft(laststart+(lastend-laststart)/2)
laststart=0
lastend=0
myoutput=deque()
对于范围内的i(1,len(y_平滑)-1):
#检测启动:
如果你顺利[我]=0和y_平滑[i-1]==0:
laststart=i
#检测结束:
elif y_光滑[我]=0和y_平滑[i+1]==0和laststart+2
EDIT:为了简化一切,我在开始时只给出了一个输入数据的简短示例。这个短列表实际上导致了一个有问题的平滑输出-整个列表将被平滑,不会留下零如您所述,查找组的一种相当简单的方法是将数据转换为布尔数组,其中1表示组内的数据,0表示组外的数据,并计算两个连续值的差,这样一来,组的开头为1,结尾为-1 下面是一个例子:
import numpy as np
mydata = [0.0, 0.0, 0.0, 0.0, 0.0, 0.143, 0.0, 0.22, 0.135, 0.44, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.33, 0.65, 0.22, 0.0, 0.0, 0.0, 0.0, 0.0]
arr = np.array(mydata)
mask = (arr!=0).astype(np.int) #array that contains 1 for every non zero value, zero other wise
padded_mask = np.pad(mask,(1,),"constant") #add a zero at the start and at the end to handle edge cases
edge_mask = padded_mask[1:] - padded_mask[:-1] #diff between a value and the following one
#if there's a 1 in edge mask it's a group start
#if there's a -1 it's a group stop
#where gives us the index of those starts and stops
starts = np.where(edge_mask == 1)[0]
stops = np.where(edge_mask == -1)[0]
print(starts,stops)
#we format groups and drop groups that are too small
groups = [group for group in zip(starts,stops) if (group[0]+2 < group[1])]
for group in groups:
print("start,stop : {} middle : {}".format(group,(group[0]+group[1])/2) )
平滑后的数据没有剩余的零:
import numpy as np
def smooth(y, box_pts):
box = np.ones(box_pts)/box_pts
print(box)
y_smooth = np.convolve(y, box, mode='same')
return y_smooth
mydata = [0.0, 0.0, 0.0, 0.0,-0.2, 0.143,
0.0, 0.22, 0.135, 0.44, 0.1, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.33, 0.65, 0.22, 0.0, 0.0, 0.0,
0.0, 0.0]
y_smooth = smooth(mydata, 27)
print(y_smooth)
输出:
[ 0.0469 0.0519 0.0519 0.0519 0.0519 0.0519
0.0519 0.0519 0.0519 0.0519 0.0684 0.1009
0.1119 0.1119 0.1119 0.1119 0.10475 0.10475
0.09375 0.087 0.065 0.06 0.06 0.06
0.06 0.06 0.06 ]
8 20
8 20
8
[8, 20]
在原始数据中找到它的一种方法是:
def findGroups(data, minGrpSize=1):
startpos = -1
endpos = -1
pospos = []
for idx,v in enumerate(mydata):
if v > 0 and startpos == -1:
startpos = idx
elif v == 0.0:
if startpos > -1:
if idx < (len(mydata)-1) and mydata[idx+1] != 0.0:
pass # ignore one 0.0 in a run
else:
endpos = idx
if startpos > -1:
if endpos >-1 or idx == len(mydata)-1: # both set or last one
if (endpos - startpos) >= minGrpSize:
pospos.append((startpos,endpos))
startpos = -1
endpos = -1
return pospos
pos = findGroups(mydata,1)
print(*map(lambda x: sum(x) // len(x), pos))
pos = findGroups(mydata,3)
print(*map(lambda x: sum(x) // len(x), pos))
pos = findGroups(mydata,5)
print(*map(lambda x: sum(x) // len(x), pos))
第2部分-找到组中点:
mydata = [0.0, 0.0, 0.0, 0.0, 0.0, 0.143, 0.0, 0.22, 0.135, 0.44, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.33, 0.65, 0.22, 0.0, 0.0, 0.0, 0.0, 0.0]
groups = []
last_start = 0
last_end = 0
in_group = 0
for i in range(1, len(mydata) - 1):
if not in_group:
if mydata[i] and not mydata[i - 1]:
last_start = i
in_group = 1
else: # a group continued.
if mydata[i]:
last_end = i
elif last_end - last_start > 1: # we have a group i.e. not single non-zero value
mid_point = (last_end - last_start) + last_start
groups.append(((last_end - last_start)//2) + last_start)
last_start, last_end, in_group = (0, 0, 0)
else: # it was just a single non-zero.
last_start, last_end, in_group = (0, 0, 0)
print(groups)
输出:
[ 0.0469 0.0519 0.0519 0.0519 0.0519 0.0519
0.0519 0.0519 0.0519 0.0519 0.0684 0.1009
0.1119 0.1119 0.1119 0.1119 0.10475 0.10475
0.09375 0.087 0.065 0.06 0.06 0.06
0.06 0.06 0.06 ]
8 20
8 20
8
[8, 20]
完整的numpy解决方案如下:(未完全优化)
我想让代码检测2组。第一组:
[0.143,0.0,0.22,0.135,0.44,0.1]
;第二组:[0.33,0.65,0.22]
。现在是中间元素的位置(如果没有真正的中间值,则从中间向左或向右)。因此,在输出中,8
将是第一组的中间,而20
将是第二组的中间。因此,一组中的一个零可以容忍为噪声,两个零分开组?完美的解决方案应该允许某种动态缩放-如果组的长度为30个元素:~5个零仍然可以算作噪声。但是如果整个组只有5个元素长,那么应该只有一个零。据我所知,我的平滑解已经是类似的了。但是没有任何选项来手动设置允许的零的数量。”平滑后的数据没有剩余的零:“哦,你是对的。我的示例数据确实导致了这种输出。我的实际工作数据要长得多(800个列表项)。平滑后,11个元素长的组最终成为24个元素的组。其他一切仍然是零。这不是一个真正的问题,因为我一直在寻找中间位置。但感谢您指出有问题的示例数据!