import numpy as np
group = np.array([0,0,0,0,1,1,1,1,1,1,2,2,2,2])
array = np.array([1,2,3,0,0,2,0,3,4,0,0,0,0,1])
targt = np.array([1,1,1,0,0,2,2,2,2,0,0,0,0,1])
def func(group: np.array, array: np.array):
pass
return array
- Step 1:找出每組的第一個和最后一個非零元素的索引,即第0組為(0, 2),第1組為(5, 8),第2組為(13, 13)。
- 步驟 2:將每個索引之間的切片替換為每個組內的第一個非零值,即組 0 [1,2,3,0] -> [1,1,1,0],組 1 [ 0,2,0,3,4,0] -> [0,2,2,2,2,0],第 2 組沒有變化。
我怎么能不拆分陣列或迭代呢?
[解決方案]
def first_nonzero_index(arr: np.array, axis: int, mode: str = None, invalid_value: float = -1):
mask = arr != 0
if mode is None or mode == "head":
return np.where(mask.any(axis=axis), mask.argmax(axis=axis), invalid_value)
else:
return np.where(mask.any(axis=axis),
arr.shape[axis] - np.flip(mask, axis=axis).argmax(axis=axis) - 1, invalid_value)
def func1(group: np.array, array: np.array): # my solution
group_size = np.bincount(group)[:-1]
group_idx_end = np.cumsum(group_size)
array_split = np.split(array, group_idx_end)
concat_list = []
for arr in array_split:
idx_start = first_nonzero_index(arr, axis=0, mode="head")
if idx_start != -1:
idx_end = first_nonzero_index(arr, axis=0, mode="tail") 1
arr_ffill_first_nonzero = np.zeros_like(arr, dtype=float)
arr_ffill_first_nonzero[idx_start:idx_end] = arr[idx_start]
concat_list.append(arr_ffill_first_nonzero)
else:
concat_list.append(arr)
return np.hstack(concat_list)
def fill(val): # contributor @d.b
inds = np.where(val != 0)[0]
start, end = min(inds), max(inds)
fill_val = val[start]
val[start:end 1] = fill_val
return val
def split(val, grp): # contributor @d.b
arr = []
curr = [val[0]]
for i in range(1, len(val)):
if grp[i] == grp[i - 1]:
curr.append(val[i])
else:
arr.append(np.array(curr))
curr = [val[i]]
if curr:
arr.append(np.array(curr))
return arr
def func2(group, array): # contributor @d.b
return np.concatenate([fill(x) for x in split(array, group)])
def func3(group: np.array, array: np.array): # my solution
group_size = np.bincount(group)[:-1]
group_idx_end = np.cumsum(group_size)
array_split = np.split(array, group_idx_end)
concat_list = []
for arr in array_split:
idx = np.where(arr != 0)[0]
start, end = min(idx), max(idx)
arr[start:end 1] = arr[start]
concat_list.append(arr)
return np.hstack(concat_list)
def func4(group, array): # contributor @d.b
nonzero = (array != 0)
_, marker_idx = np.unique(group[nonzero], return_index=True)
nonzero_idx = np.arange(len(array))[nonzero]
#STEP 2
starts = np.minimum.reduceat(nonzero_idx, marker_idx)
ends = np.maximum.reduceat(nonzero_idx, marker_idx)
#STEP 3
values = array[starts]
out = np.zeros_like(array)
out[starts] = values
#check the case we can't insert the last negative value
if ends[-1] 1==len(array):
out[ends[:-1] 1] = -values[:-1]
else:
out[ends 1] = -values
return np.cumsum(out)
輸出:[1。1. 1. 0. 0. 2. 2. 2. 2. 0. 0. 0. 0. 1.]
[測驗]
n = 2000
group = np.array([0,0,0,0,1,0,0,0,0,1,0,0,0,0,0]*n) # 30000
array = np.array([1,2,3,0,0,2,0,3,0,0,0,0,0,1,0]*n)
group = np.cumsum(group)
運行 100 次:
| 功能1 | 功能2 | 功能3 | func4(最佳解決方案) |
|---|---|---|---|
| 9.70s | 2.54s | 1.99s | 0.03s |
uj5u.com熱心網友回復:
group = np.array([0,0,0,0,1,1,1,1,1,1,2,2,2,2])
array = np.array([1,2,3,0,0,2,0,3,4,0,0,0,0,1])
targt = np.array([1,1,1,0,0,2,2,2,2,0,0,0,0,1])
您可以執行以下步驟:
STEP 1. 找到非零項的索引
array并標記新組的開始nonzero_idx -> [*0,1,2,/,*/,5,/,7,8,/,*/,/,/,13] (cross out slashes) marker_idx -> [0, 4, 10]STEP 2. 找到每個組的開始和結束索引,使用
np.ufunc.reduceatstarts -> [ 0, 5, 13] ends -> [ 2, 8, 13]步驟 3. 考慮一個
out可以np.cumsum(out)折疊成target陣列的陣列。像這樣:[1,0,0,-1,0,2,0,0,0,-2,0,0,0,1] -> [1,1,1,0,0,2,2,2,2,0,0,0,0,1]
現在,代碼:
#STEP 1
nonzero = (array != 0)
_, marker_idx = np.unique(group[nonzero], return_index=True)
nonzero_idx = np.arange(len(array))[nonzero]
#STEP 2
starts = np.minimum.reduceat(nonzero_idx, marker_idx)
ends = np.maximum.reduceat(nonzero_idx, marker_idx)
#STEP 3
values = array[starts]
out = np.zeros_like(array)
out[starts] = values
#check the case we can't insert the last negative value
if ends[-1] 1==len(array):
out[ends[:-1] 1] = -values[:-1]
else:
out[ends 1] = -values
>>> np.cumsum(out)
array([1, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1], dtype=int32)
不需要回圈!
uj5u.com熱心網友回復:
1
import numpy as np
import pandas as pd
def foo(s):
chk = np.where(s > 0)[0]
start = min(chk)
end = max(chk)
ans = [True if (start <= ind <= end) else False for ind in range(len(s))]
return ans
pd.Series(array).groupby(group).transform(
lambda x: x.mask(foo(x), x[x > 0].iloc[0])).to_numpy()
# array([1, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1])
2
def split(val, grp):
inds = np.where(np.append(False, grp[1:] != grp[:-1]))[0]
return np.array_split(val, inds)
def fill(val):
inds = np.where(val > 0)[0]
start, end = min(inds), max(inds)
val[start:end 1] = val[start]
return val
np.concatenate([fill(x) for x in split(array, group)])
# array([1, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1])
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/364822.html
上一篇:比較兩個多字文本字串的陣列公式
