我必须处理大量数据。每行以1或0开头。我需要一个数据行,其中每行以1开头,因此我必须将所有行的值左移,直到第一个值为1。
例如:
0 1 0 0 1 0 0
1 0 0 0 0 1 1
0 0 0 1 0 0 1
0 0 0 0 0 1 1
结果必须是这样的:
1 0 0 1 0 0 0
1 0 0 0 0 1 1
1 0 0 1 0 0 0
1 1 0 0 0 0 0
我不想用于,等,因为我需要使用pandas或numpy的更快的方法。
您对这个问题有想法吗?
答案 0 :(得分:4)
您可以将cummax
与NaN
和sorted
一起使用以掩盖所有需要平移的位置
df[df.cummax(1).ne(0)].apply(lambda x : sorted(x,key=pd.isnull),1).fillna(0).astype(int)
Out[310]:
1 2 3 4 5 6 7
0 1 0 0 1 0 0 0
1 1 0 0 0 0 1 1
2 1 0 0 1 0 0 0
3 1 1 0 0 0 0 0
或者我们使用由 Divakar 编写的函数justify(比应用排序快得多)
pd.DataFrame(justify(df[df.cummax(1).ne(0)].values, invalid_val=np.nan, axis=1, side='left')).fillna(0).astype(int)
Out[314]:
0 1 2 3 4 5 6
0 1 0 0 1 0 0 0
1 1 0 0 0 0 1 1
2 1 0 0 1 0 0 0
3 1 1 0 0 0 0 0
答案 1 :(得分:3)
您可以在此处使用numpy.ogrid
:
foreach($json['included'] as $key => $title) {
$cusa = substr(explode('-', $title['id'], 3)[1], 0, -3);
if($title['type'] == 'game' && substr($cusa, 0, 4) == 'CUSA') {
// if the day of release has already passed, skip
if (strtotime(date('Y-m-d H:i:s')) > strtotime($title['attributes']['release-date'])) continue;
?>
<div class="game-banner" style="background:url(<?php echo $title['attributes']['thumbnail-url-base']; ?>)">
<h4 class="psplus-game-name"><?php echo $title['attributes']['name']; ?></h4>
</div>
<?php
if($key >= 4) break; // display only 3
}
}
}
a = df.values
s = a.argmax(1) * - 1
m, n = a.shape
r, c = np.ogrid[:m, :n]
s[s < 0] += n
c = c - s[:, None]
a[r, c]
时间
array([[1, 0, 0, 1, 0, 0, 0],
[1, 0, 0, 0, 0, 1, 1],
[1, 0, 0, 1, 0, 0, 0],
[1, 1, 0, 0, 0, 0, 0]], dtype=int64)
答案 2 :(得分:2)
为了提高性能,您可以使用numba
。一个基本循环,但是在JIT编译和在C级别使用更多基本对象的情况下有效:
from numba import njit
@njit
def shifter(A):
res = np.zeros(A.shape)
for i in range(res.shape[0]):
start, end = 0, 0
for j in range(res.shape[1]):
if A[i, j] != 0:
start = j
break
res[i, :res.shape[1]-start] = A[i, start:]
return res
性能基准化
def jpp(df):
return pd.DataFrame(shifter(df.values).astype(int))
def user348(df):
a = df.values
s = a.argmax(1) * - 1
m, n = a.shape
r, c = np.ogrid[:m, :n]
s[s < 0] += n
c = c - s[:, None]
return pd.DataFrame(a[r, c])
np.random.seed(0)
df = pd.DataFrame(np.random.randint(0, 2, (1000, 1000)))
assert np.array_equal(jpp(df).values, user348(df).values)
%timeit jpp(df) # 9.2 ms per loop
%timeit user348(df) # 18.5 ms per loop
答案 3 :(得分:2)
这是一个stride_tricks
解决方案,它之所以快速,是因为它支持逐片复制。
def pp(x):
n, m = x.shape
am = x.argmax(-1)
mam = am.max()
xx = np.empty((n, m + mam), x.dtype)
xx[:, :m] = x
xx[:, m:] = 0
xx = np.lib.stride_tricks.as_strided(xx, (n, mam+1, m), (*xx.strides, xx.strides[-1]))
return xx[np.arange(x.shape[0]), am]
它用所需的零填充空白,然后使用as_strided
创建滑动窗口视图。使用花式索引可以解决此问题,但是由于最后一个维度没有索引,因此行的复制得到了优化和快速。
多快?对于与numba相等的足够大的输入:
x = np.random.randint(0, 2, (10000, 10))
from timeit import timeit
shifter(x) # that should compile it, right?
print(timeit(lambda:shifter(x).astype(x.dtype), number=1000))
print(timeit(lambda:pp(x), number=1000))
示例输出:
0.8630472810036736
0.7336142909916816