切片字典的键来分配数据
Slicing keys of a dictionary to assign data
现在我正在通过以下循环填充字典:
import numpy as np
data = np.random.choice(2, 10)
output = dict()
for i in range(10):
output[i] = data[i]
有没有更有效的方法来体现 output[:] = data[:]
的精神?
解决方案:output = dict(zip(range(10), np.random.choice(2, 10)))
跟进:
如果键是元组怎么办?
import numpy as np
data = np.random.choice(2, 10)
output = dict()
for i in range(10):
output[1, i] = data[i]
关注-跟进:
我试图将我的实际问题减少到最低限度,但最终没有问我想问的问题。我实际做的是以下内容:
import numpy as np
output = dict()
for j in range(2):
for k in range(3):
data = np.random.choice(2, 10)
for i in range(10):
output[j, k, i] = data[i]
我尝试循环使用答案,但出现名称错误。
output = dict(zip(range(10), np.random.choice(2, 10)))
这使得 range(10)
中的每个元素都成为键,np.random.choice(2, 10)
中的元素作为值。
如果你想要一个作为元组的键,你可以将生成器传递给 zip
,它将“预创建”可迭代的元组:
output = dict(zip(((1, i) for i in range(10)), np.random.choice(2, 10)))
另一种可读性较差的替代方法是 map
:
output = dict(zip(map(lambda n: (1, n), range(10)), np.random.choice(2, 10)))
编辑(看到“follow-follow up”后):
如果你想要更高维度的元组,根据你的“后续跟进”问题:
def gen_nd(size):
n = np.product(size)
data = np.random.choice(2, n).tolist()
idx = np.unravel_index(np.arange(n, dtype=int), size)
return dict(zip(list(zip(*idx)), data))
>>> gen_nd((2,3,2))
{(0, 0, 0): 0,
(0, 0, 1): 0,
(0, 1, 0): 1,
(0, 1, 1): 1,
(0, 2, 0): 0,
(0, 2, 1): 1,
(1, 0, 0): 0,
(1, 0, 1): 0,
(1, 1, 0): 0,
(1, 1, 1): 0,
(1, 2, 0): 0,
(1, 2, 1): 1}
还有:
%timeit gen_nd((100, 100, 100))
647 ms ± 1.02 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
另外 2 倍加速:
def gen_nd(size):
m = len(size)
n = np.product(size)
data = np.random.choice(2, n).tolist()
ranges = [np.arange(k) for k in size]
idx = np.stack(np.meshgrid(*ranges, indexing='ij'), -1).reshape(-1, m).T.tolist()
return dict(zip(list(zip(*idx)), data))
%timeit gen_nd((100, 100, 100))
297 ms ± 423 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
原回答
简单(可读且快速)怎么样:
data = np.random.choice(2, 10)
output = dict(enumerate(data.tolist()))
对于 tuple
键(“跟进问题”):
output = {(1, k): v for k, v in enumerate(data.tolist())}
速度
如果您对速度感兴趣,那么这里有一个有趣的基准测试:
def gen0(n):
return dict(enumerate(data))
def tupgen0(n):
data = np.random.choice(2, n)
{(1,k): v for k, v in enumerate(data)}
def gen1(n):
data = np.random.choice(2, n)
return dict(enumerate(data.tolist()))
def tupgen1(n):
data = np.random.choice(2, n)
{(1,k): v for k, v in enumerate(data.tolist())}
def gen2(n):
data = np.stack((np.arange(n, dtype=int), np.random.choice(2, n)))
return dict(zip(*data.tolist()))
def tupgen2(n):
data = np.stack((np.ones(n, dtype=int), np.arange(n, dtype=int), np.random.choice(2, n)))
k, v = data[:2].tolist(), data[-1].tolist()
return dict(zip(tuple(zip(*k)), v))
def gen3(n):
return dict(zip(range(n), np.random.choice(2, n)))
def tupgen3(n):
return dict(zip(((1, i) for i in range(n)), np.random.choice(2, n)))
n = 1_000_000
g0 = %timeit -o gen0(n)
g1 = %timeit -o gen1(n)
g2 = %timeit -o gen2(n)
g3 = %timeit -o gen3(n)
t0 = %timeit -o tupgen0(n)
t1 = %timeit -o tupgen1(n)
t2 = %timeit -o tupgen2(n)
t3 = %timeit -o tupgen3(n)
给出:
202 ms ± 256 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
114 ms ± 37.3 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
139 ms ± 53.9 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
203 ms ± 212 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
350 ms ± 721 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
245 ms ± 321 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
305 ms ± 699 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
375 ms ± 2.13 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
所以方法 gen1()
和 tupgen1()
在它们的 class 中是最快的。
现在我正在通过以下循环填充字典:
import numpy as np
data = np.random.choice(2, 10)
output = dict()
for i in range(10):
output[i] = data[i]
有没有更有效的方法来体现 output[:] = data[:]
的精神?
解决方案:output = dict(zip(range(10), np.random.choice(2, 10)))
跟进: 如果键是元组怎么办?
import numpy as np
data = np.random.choice(2, 10)
output = dict()
for i in range(10):
output[1, i] = data[i]
关注-跟进: 我试图将我的实际问题减少到最低限度,但最终没有问我想问的问题。我实际做的是以下内容:
import numpy as np
output = dict()
for j in range(2):
for k in range(3):
data = np.random.choice(2, 10)
for i in range(10):
output[j, k, i] = data[i]
我尝试循环使用答案,但出现名称错误。
output = dict(zip(range(10), np.random.choice(2, 10)))
这使得 range(10)
中的每个元素都成为键,np.random.choice(2, 10)
中的元素作为值。
如果你想要一个作为元组的键,你可以将生成器传递给 zip
,它将“预创建”可迭代的元组:
output = dict(zip(((1, i) for i in range(10)), np.random.choice(2, 10)))
另一种可读性较差的替代方法是 map
:
output = dict(zip(map(lambda n: (1, n), range(10)), np.random.choice(2, 10)))
编辑(看到“follow-follow up”后):
如果你想要更高维度的元组,根据你的“后续跟进”问题:
def gen_nd(size):
n = np.product(size)
data = np.random.choice(2, n).tolist()
idx = np.unravel_index(np.arange(n, dtype=int), size)
return dict(zip(list(zip(*idx)), data))
>>> gen_nd((2,3,2))
{(0, 0, 0): 0,
(0, 0, 1): 0,
(0, 1, 0): 1,
(0, 1, 1): 1,
(0, 2, 0): 0,
(0, 2, 1): 1,
(1, 0, 0): 0,
(1, 0, 1): 0,
(1, 1, 0): 0,
(1, 1, 1): 0,
(1, 2, 0): 0,
(1, 2, 1): 1}
还有:
%timeit gen_nd((100, 100, 100))
647 ms ± 1.02 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
另外 2 倍加速:
def gen_nd(size):
m = len(size)
n = np.product(size)
data = np.random.choice(2, n).tolist()
ranges = [np.arange(k) for k in size]
idx = np.stack(np.meshgrid(*ranges, indexing='ij'), -1).reshape(-1, m).T.tolist()
return dict(zip(list(zip(*idx)), data))
%timeit gen_nd((100, 100, 100))
297 ms ± 423 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
原回答
简单(可读且快速)怎么样:
data = np.random.choice(2, 10)
output = dict(enumerate(data.tolist()))
对于 tuple
键(“跟进问题”):
output = {(1, k): v for k, v in enumerate(data.tolist())}
速度
如果您对速度感兴趣,那么这里有一个有趣的基准测试:
def gen0(n):
return dict(enumerate(data))
def tupgen0(n):
data = np.random.choice(2, n)
{(1,k): v for k, v in enumerate(data)}
def gen1(n):
data = np.random.choice(2, n)
return dict(enumerate(data.tolist()))
def tupgen1(n):
data = np.random.choice(2, n)
{(1,k): v for k, v in enumerate(data.tolist())}
def gen2(n):
data = np.stack((np.arange(n, dtype=int), np.random.choice(2, n)))
return dict(zip(*data.tolist()))
def tupgen2(n):
data = np.stack((np.ones(n, dtype=int), np.arange(n, dtype=int), np.random.choice(2, n)))
k, v = data[:2].tolist(), data[-1].tolist()
return dict(zip(tuple(zip(*k)), v))
def gen3(n):
return dict(zip(range(n), np.random.choice(2, n)))
def tupgen3(n):
return dict(zip(((1, i) for i in range(n)), np.random.choice(2, n)))
n = 1_000_000
g0 = %timeit -o gen0(n)
g1 = %timeit -o gen1(n)
g2 = %timeit -o gen2(n)
g3 = %timeit -o gen3(n)
t0 = %timeit -o tupgen0(n)
t1 = %timeit -o tupgen1(n)
t2 = %timeit -o tupgen2(n)
t3 = %timeit -o tupgen3(n)
给出:
202 ms ± 256 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
114 ms ± 37.3 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
139 ms ± 53.9 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
203 ms ± 212 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
350 ms ± 721 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
245 ms ± 321 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
305 ms ± 699 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
375 ms ± 2.13 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
所以方法 gen1()
和 tupgen1()
在它们的 class 中是最快的。