我编写了一个用户定义的函数,该函数循环遍历一行值,以便给出值之间的零数(值之间的距离)。这些距离将追加到列表中,然后取平均值,得出值之间平均距离的最终值。当我加载只有一行值的 CSV 文件时,该函数效果很好。但是,我希望能够将该函数应用于具有多行的文件,然后将每行的输出报告到数据帧中。
这一切都是在python 3.7上运行的。我尝试创建一个嵌套循环,以便手动应用该函数。我已经尝试了numpy.apply_along_axis功能。我还尝试将文件作为熊猫数据帧读取,然后使用 .apply() 函数。但是,我对熊猫有点不熟悉,当我用熊猫索引替换函数中的numpy索引时,我开始生成多个错误。
例如,当我加载一个更大的 CSV 文件并尝试将其应用于文件 [0] 时,该功能不起作用。它似乎仅在我加载具有一行值的文件中时才有效。
def avg_dist():
import statistics as st
dist = []
ctr=0
#distances between events
for i in range(len(n)):
if n[i] > 0 and i < (len(n)-1):
if n[i+1]==0:
i+=1
while n[i]==0 and i < (len(n)-1):
ctr+=1
i+=1
dist.append(ctr)
ctr=0
else:
i+=1
else:
i+=1
#Average distance between events
aved = st.mean(dist)
return(aved)
最新的回复在答案的末尾。 已经进行了几次编辑。
答案的最后(第 4 次编辑)采用了全新的方法。
我不确定你想做什么,但希望这可以有所帮助。
import numpy as np
# Generate some events
events = np.random.rand(3,12)*10.
events *= np.random.randint(5, size=(3,12))<1
events
Out[36]:
array([[ 0. , 0. , 0. , 0. , 0. ,
0. , 5.35598205, 0. , 0. , 0. ,
0. , 0. ],
[ 0. , 6.65094145, 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. ,
0. , 6.04581361],
[ 6.88119682, 4.31178109, 0. , 0. , 0. ,
0. , 0. , 1.16999289, 0. , 0. ,
0. , 0. ]])
# generate a boolean array of events. (as int for a compact print.)
an_event = (events != 0).astype(np.int)
n_event
Out[37]:
array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]])
def event_range(arr):
from_start = arr.cumsum(axis=1)
from_end = np.flip(arr, axis=1).cumsum(axis=1)
from_end = np.flip(from_end, axis=1)
return np.logical_and(from_start, from_end).astype(np.int)
event_range逐步发挥作用。
from_start是an_event的总和。 任何事件之前为零,之后为>0。
from_start = an_event.cumsum(axis=1) # cumsum the event count. zeros before the first event.
from_start
Out[40]:
array([[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], # zeroes before the first event.
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3]], dtype=int32)
from_end是an_event的累积总和,但从最大值到最小值。因此,在最后一个事件之后为零。
from_end = np.flip(an_event, axis=1).cumsum(axis=1) # cumsum of reversed arrays
from_end = np.flip(from_end, axis=1) # reverse the result.
from_end
Out[41]:
array([[1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], # zero after the last event.
[2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[3, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]], dtype=int32)
从逻辑上讲,将这些放在一起得到,第一个事件之前的零,之后的 1,最后一个事件之后的零。
ev_range = np.logical_and(from_start, from_end).astype(np.int)
ev_range
Out[42]:
# zero before first and after last event, one between the events.
array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]])
n_range = ev_range.sum(axis=1)
n_range
Out[43]: array([ 1, 11, 8])
n_events = an_event.sum(axis=1)
n_events
Out[44]: array([1, 2, 3])
avg = n_range / n_events
avg
Out[45]: array([ 1. , 5.5 , 2.66666667])
avg 应该n_range/(n_events-1)吗?即计算差距,而不是事件。
对于连续一个事件,您会期望什么? 连续零事件怎么办?
编辑以下评论
计算比零更长的差距会有点复杂。 最简单的方法可能是获取连续列的差异。 如果这些是 -1,则有一个 1 后跟一个零。 您需要向数据添加最后的零列,以防最后一列中包含事件。
np.random.seed(10)
test = 1*(np.random.randint(4, size=(4,12))<1)
test
Out[24]:
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1],
[0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]])
temp = np.diff(test, axis=-1)
temp
Out[26]:
array([[ 0, 1, -1, 1, -1, 0, 1, -1, 0, 1, -1],
[ 0, 1, -1, 1, -1, 1, -1, 1, -1, 1, 0],
[ 0, 0, 1, -1, 0, 0, 0, 1, 0, -1, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0]])
np.where(temp<0, 1,0)
Out[28]:
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]])
In [29]: np.where(temp<0, 1,0).sum(axis=-1)-1
Out[29]: array([3, 3, 1, 0]) # should be [3, 4, 1, 0]
添加一列零进行测试。
test = np.hstack((test, np.zeros((4,1), dtype = np.int)))
test
Out[31]:
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]])
temp=np.diff(test, axis=-1)
temp
Out[35]:
array([[ 0, 1, -1, 1, -1, 0, 1, -1, 0, 1, -1, 0],
[ 0, 1, -1, 1, -1, 1, -1, 1, -1, 1, 0, -1], # An extra -1 here.
[ 0, 0, 1, -1, 0, 0, 0, 1, 0, -1, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0]])
np.where(temp<0, 1,0).sum(axis=-1)-1
Out[36]: array([3, 4, 1, 0])
正如我所说,有点牵扯。 循环访问可能更容易,但如果更难理解,这应该更快。
第二次编辑遵循另一个想法。
import numpy as np
np.random.seed(10)
test = 1*(np.random.randint(4, size=(4,12))<1)
test
Out[2]:
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1],
[0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]])
temp = np.diff(test, axis=-1)
np.where(temp<0, 1, 0).sum(axis=-1)+test[:,-1]-1
# +test[:,-1] adds the last column to include any 1's from there.
Out[4]: array([3, 4, 1, 0])
第三次编辑
考虑到这一点,我创建了 2 个函数,我还展示了一个应对除以零的do_divide。
import numpy as np
def zero_after_last_event(arr):
"""
Returns an array set to zero in all cells after the last event
"""
from_end = np.flip(arr, axis=-1).cumsum(axis=-1) # cumsum of reversed arrays
from_end = np.flip(from_end, axis=-1) # reverse the result.
from_end[from_end>0] = 1 # gt zero set to 1
return from_end
def event_range(arr):
""" event_range is zero before the first event,
zero after the last event and 1 elsewhere. """
return np.logical_and(arr.cumsum(axis=-1), zero_after_last_event(arr)).astype(np.int)
def do_divide(a, b):
""" Does a protected divide. Returns zero for divide by zero """
with np.errstate(invalid='ignore'): # Catch divide by zero
result = a / b
result[~np.isfinite(result)] = 0.
return result
设置测试阵列
np.random.seed(10)
events = 1*(np.random.randint(4, size=(4,12))<1)
events
Out[15]:
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1],
[0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]])
使用上面的函数和数据,如下所示。
# Count gap lengths
gaps = 1 - events # invert the values in events (1->0, 0->1)
gaps = np.logical_and(gaps, event_range(events)).astype(np.int)
gaps
Out[19]:
array([[0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0],
[0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
sumgaps = gaps.sum(axis = -1)
sumgaps
Out[22]: array([5, 4, 4, 0])
# Count how many gaps
temp = np.diff(events, axis=-1) # temp is -1 when an event isn't immediately followed by another event.
n_gaps = np.where(temp<0, 1, 0).sum(axis=-1)+events[:,-1]-1
# +test[:,-1] adds the last column to include any 1's from there.
n_gaps
Out[23]: array([3, 4, 1, 0])
do_divide(sum_gaps, n_gaps)
Out[21]: array([1.66666667, 1. , 4. , 0. ])
第 4 次编辑 - 使用 np.bincount
import numpy as np
def do_divide(a, b):
""" Does a protected divide. Returns zero for divide by zero """
with np.errstate(invalid='ignore'): # Catch divide by zero
result = a / b
result[~np.isfinite(result)] = 0.
return result
np.random.seed(10)
events = 1*(np.random.randint(4, size=(4,12))<1)
cumulative = events.cumsum(axis=1)
cumulative
Out[2]:
array([[0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4],
[0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6],
[0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 3, 3],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1]])
bin_count_len = 1+cumulative.max() # Biggest bins length required.
result = np.zeros((cumulative.shape[0], bin_count_len), dtype=np.int)
for ix, row in enumerate(cumulative):
result[ix] = np.bincount( row, minlength = bin_count_len )
result
Out[4]:
array([[2, 2, 3, 3, 2, 0, 0],
[2, 2, 2, 2, 2, 1, 1],
[3, 5, 1, 3, 0, 0, 0],
[9, 3, 0, 0, 0, 0, 0]])
丢失第 0 列。 它在任何事件之前。丢失最后一列,始终在最后一个事件之后。缺口包括开盘事件,-1 将其从缺口大小中删除。
temp = result[:, 1:-1]-1 #
temp
Out[6]:
array([[ 1, 2, 2, 1, -1],
[ 1, 1, 1, 1, 0],
[ 4, 0, 2, -1, -1],
[ 2, -1, -1, -1, -1]])
如果温度[r, n+1]==0,则设置任何单元格温度[r, n] = 0
temp_lag = (result[:, 2:]>0)*1
temp_lag
Out[8]:
array([[1, 1, 1, 0, 0],
[1, 1, 1, 1, 1],
[1, 1, 0, 0, 0],
[0, 0, 0, 0, 0]])
temp *= temp_lag
temp
Out[10]:
array([[1, 2, 2, 0, 0],
[1, 1, 1, 1, 0],
[4, 0, 0, 0, 0],
[0, 0, 0, 0, 0]])
tot_gaps = temp.sum(axis=1)
n_gaps = np.count_nonzero(temp, axis=1)
tot_gaps, n_gaps
Out[13]: (array([5, 4, 4, 0]), array([3, 4, 1, 0]))
do_divide(tot_gaps, n_gaps)
Out[14]: array([1.66666667, 1. , 4. , 0. ])
呵呵