頭の体操

Add the indexes of an unknown amount of lists (Python 3) – StackOverflow

list_a = [1,2,3,4,5]
list_b = [2,4,6,8,10]
list_c = [3,6,9,12,15]

[sum(x) for x in zip(list_a, list_b, list_c)]

[6, 12, 18, 24, 30]
 
 
 

Rolling window in python – StackOverflow

li = [1,2,3,4,5,6]

[li[i:i+3] for i in range(len(li)-2)]

[[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]

numpy.lib.stride_tricks.as_stridedは1Dでも2Dでもスライス操作さえしっかりイメージできれば非常に便利な反面,「Warning:This function has to be used with extreme care, see notes.」と書かれている様に,取り扱いに気をつけないといけない.

あまり,as_stridedを使う場面って無い様な.Window sizeが欲しい時とか,要は畳み込みしたい場合とかだけど,それならconvolveがあるし.

import numpy as np

np.convolve(li, [1, 1, 1])
np.convolve(li, [1, 1, 1], 'same')
np.convolve(li, [1, 1, 1], 'valid')

array([ 1, 3, 6, 9, 12, 15, 11, 6])
array([ 3, 6, 9, 12, 15, 11])
array([ 6, 9, 12, 15])
 
 
 

python combine multiple sublist in to single list by group – StackOverflow

気づいたら質問内容変わっているけど,後の質問は単に

[i for sl in list(zip(*[x for sublist in li for x in sublist])) for i in sl]
#list(itertools.chain.from_iterable(zip(*itertools.chain.from_iterable(li))))

[‘2017-08-08 10:00:38’,
‘2017-08-08 10:05:38’,
‘2017-08-08 10:10:38’,
‘2017-08-08 10:15:38’,
‘2017-08-08 10:20:38’,
‘2017-08-08 10:25:38’,
‘2017-08-08 10:30:38’,
‘2017-08-08 10:35:38’,
‘2017-08-08 10:40:38’,
‘2017-08-08 10:45:38’,
‘2017-08-08 10:50:38’,
‘2017-08-08 10:55:38’,
‘2017-08-08 11:00:38’,
‘2017-08-08 10:00:38’,
‘2017-08-08 10:05:38’,
‘2017-08-08 10:10:38’,
‘2017-08-08 10:15:38’,
‘2017-08-08 10:25:38’,
‘2017-08-08 10:30:38’,
‘2017-08-08 10:35:38’,
‘2017-08-08 10:45:38’,
‘2017-08-08 10:50:38’,
‘2017-08-08 10:55:38’,
‘2017-08-08 11:00:38’,
5.0,
8.0,
7.5,
8.3,
5.0,
5.0,
5.0,
5.0,
55.0,
85.0,
55.0,
5.0,
53.0,
11.2,
10.0,
10.0,
101.0,
10.0,
10.0,
110.0,
100.5,
100.5,
10.05,
10.1]

だけの話で,最初の質問の方が面白いのでその方向で考える.

li = [[('2017-08-08 10:00:38', 5.0), ('2017-08-08 10:05:38', 8.0), ('2017-08-08 10:10:38', 7.5), ('2017-08-08 10:15:38', 8.3), ('2017-08-08 10:20:38', 5.0), ('2017-08-08 10:25:38', 5.0), ('2017-08-08 10:30:38', 5.0), ('2017-08-08 10:35:38', 5.0), ('2017-08-08 10:40:38', 55.0), ('2017-08-08 10:45:38', 85.0), ('2017-08-08 10:50:38', 55.0), ('2017-08-08 10:55:38', 5.0), ('2017-08-08 11:00:38', 53.0)], 
    [('2017-08-08 10:00:38', 11.2), ('2017-08-08 10:05:38', 10.0), ('2017-08-08 10:10:38', 10.0), ('2017-08-08 10:15:38', 101.0), ('2017-08-08 10:25:38', 10.0), ('2017-08-08 10:30:38', 10.0), ('2017-08-08 10:35:38', 110.0), ('2017-08-08 10:45:38', 100.5), ('2017-08-08 10:50:38', 100.5), ('2017-08-08 10:55:38', 10.05), ('2017-08-08 11:00:38', 10.10)]]

 
 
 

from itertools import chain, groupby

data = sorted(chain.from_iterable(li), key=lambda x: x[0])
groups = [(k, [x[1] for x in g]) for k, g in groupby(data, lambda x: x[0])]

[(‘2017-08-08 10:00:38’, [5.0, 11.2]),
(‘2017-08-08 10:05:38’, [8.0, 10.0]),
(‘2017-08-08 10:10:38’, [7.5, 10.0]),
(‘2017-08-08 10:15:38’, [8.3, 101.0]),
(‘2017-08-08 10:20:38’, [5.0]),
(‘2017-08-08 10:25:38’, [5.0, 10.0]),
(‘2017-08-08 10:30:38’, [5.0, 10.0]),
(‘2017-08-08 10:35:38’, [5.0, 110.0]),
(‘2017-08-08 10:40:38’, [55.0]),
(‘2017-08-08 10:45:38’, [85.0, 100.5]),
(‘2017-08-08 10:50:38’, [55.0, 100.5]),
(‘2017-08-08 10:55:38’, [5.0, 10.05]),
(‘2017-08-08 11:00:38’, [53.0, 10.1])]

%%timeit
data = sorted(chain.from_iterable(li), key=lambda x: x[0])
groups = [(k, [x[1] for x in g]) for k, g in groupby(data, lambda x: x[0])]

26.4 µs ± 1.01 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%%timeit
groups = []
data = sorted(chain.from_iterable(li), key=lambda x: x[0])
for k, g in groupby(data, lambda x: x[0]):
    temp = []
    for x in g:
        temp.append(x[1])
    groups.append((k, temp))

27.8 µs ± 961 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

groupbyも便利だけど,何かをキーにして値を纏めたい場合はまず辞書型が思い浮かぶだろう.
辞書はセットされているキーに対して代入したり,updateしたり,どの方法でも上書きになってしまうけど,モジュールを使わなくても,setdefaultをうまく使えば,既にあるキーに対して複数のバリューをセットできる(或いは内包表記でループを何回も回す方法).でも,それらは効率的ではないので(setdefaultの方法はドキュメントにも書いてあって,でもそういう場合はdefaultdict使った方が効率的とか書いてあった様な気がする;8.3.4.1. defaultdict の使用例-Python3.6.1ドキュメント),そういうことがしたい時には,defaultdictを使うといい(関連:辞書のkeyとvalueを入れ替え).

from collections import defaultdict

cl = chain.from_iterable(li)
dd = defaultdict(list)
for k, v in cl:
    dd[k].append(v)

defaultdict(list,
{‘2017-08-08 10:00:38’: [5.0, 11.2],
‘2017-08-08 10:05:38’: [8.0, 10.0],
‘2017-08-08 10:10:38’: [7.5, 10.0],
‘2017-08-08 10:15:38’: [8.3, 101.0],
‘2017-08-08 10:20:38’: [5.0],
‘2017-08-08 10:25:38’: [5.0, 10.0],
‘2017-08-08 10:30:38’: [5.0, 10.0],
‘2017-08-08 10:35:38’: [5.0, 110.0],
‘2017-08-08 10:40:38’: [55.0],
‘2017-08-08 10:45:38’: [85.0, 100.5],
‘2017-08-08 10:50:38’: [55.0, 100.5],
‘2017-08-08 10:55:38’: [5.0, 10.05],
‘2017-08-08 11:00:38’: [53.0, 10.1]})

%%timeit
cl = chain.from_iterable(li)
dd = defaultdict(list)
for k, v in cl:
    dd[k].append(v)

10.6 µs ± 86.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

非常に効率的.
 
 
 

Most elegant way to check if number is in a list of ranges and output a value – StackOverflow

1:1の対応マップを作りたい場合は回答者の通りだろうけど,質問の意図を考えたときに,タイトル通りだと,もっとシンプルな話で,

def test(x):
    if x in range(1, 5):
        return 'A'
    if x in range(6, 10):
        return 'B'
    if x in range(11, 15):
        return 'C'


def test2(x):
    ranges = [(range(1, 5), 'A'), (range(6, 10), 'B'), (range(11, 15), 'C')]
    dic = {i : v for k, v in ranges for i in k}
    return dic[x]


%timeit test(4)
%timeit test2(4)

713 ns ± 17.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
4.23 µs ± 139 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit test(12)
%timeit test2(12)

1.72 µs ± 164 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
4.14 µs ± 18 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

もちろん,

%timeit dic[4]
%timeit dic[12]

76.5 ns ± 3.4 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
77.5 ns ± 6.46 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

でも,それを言い出したら,

%%cython

def c_test(x):
    if x in range(1, 5):
        return 'A'
    if x in range(6, 10):
        return 'B'
    if x in range(11, 15):
        return 'C'
%%cython
def c_test2(x):
    ranges = [(range(1, 5), 'A'), (range(6, 10), 'B'), (range(11, 15), 'C')]
    dic = {i : v for k, v in ranges for i in k}
    return dic[x]
%timeit c_test(4)
%timeit c_test2(4)

455 ns ± 12.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
2.42 µs ± 30.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

辞書は高機能なので,高速化し難い.

%%cython

cdef _c_test3(int x):
    cdef int a, b, c
    for a in range(1, 5):
        if x == a:
            return 'A'
    for b in range(6, 10):
        if x == b:
            return 'B'
    for c in range(11, 15):
        if x == c:
            return 'C'


def c_test3(x):
    return _c_test3(x)
%timeit c_test3(4)

97.2 ns ± 1.77 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

「char*」しない方が速い.

間違えた.unicodeか.

%%cython -a

cdef unicode _c_test4(int x):
    cdef int a, b, c
    for a in range(1, 5):
        if x == a:
            return 'A'
    for b in range(6, 10):
        if x == b:
            return 'B'
    for c in range(11, 15):
        if x == c:
            return 'C'


def c_test4(x):
    return _c_test4(x)
%timeit c_test4(4)

89.9 ns ± 2.11 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

%%cython -a

cdef char* _c_test5(int x):
    cdef int a, b, c
    cdef char* A = 'A'
    cdef char* B = 'B'
    cdef char* C = 'C'
    for a in range(1, 5):
        if x == a:
            return A
    for b in range(6, 10):
        if x == b:
            return B
    for c in range(11, 15):
        if x == c:
            return C


def c_test5(x):
    return _c_test5(x)
%timeit c_test5(4)

95.4 ns ± 1.92 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

 
 
 
Cythonでline_profilerを使おうと思うと,

%load_ext line_profiler
#or
import line_profiler
###
import Cython.Compiler.Options

Cython.Compiler.Options.get_directive_defaults()['profile'] = True
Cython.Compiler.Options.get_directive_defaults()['linetrace'] = True
Cython.Compiler.Options.get_directive_defaults()['binding'] = True

###compile
%%cython -a -f --compile-args=-DCYTHON_TRACE=1

###line profiler
profile = line_profiler.LineProfiler(proc)
profile.runcall(proc, args)
profile.print_stats()
#or
%lprun -f proc proc(args)
###

ただ,プロファイリングを有効にすると,オーバーヘッドにより遅くなる可能性がある(Profiling – Cython

%%cython -a -f --compile-args=-DCYTHON_TRACE=1

cdef unicode _c_test8(int x):
    cdef int a, b, c
    for a in range(1, 5):
        if x == a:
            return 'A'
    for b in range(6, 10):
        if x == b:
            return 'B'
    for c in range(11, 15):
        if x == c:
            return 'C'


def c_test8(x):
    return _c_test8(x)
%timeit c_test8(4)

160 ns ± 3.29 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

%%cython

cdef unicode _c_test8(int x):
    cdef int a, b, c
    for a in range(1, 5):
        if x == a:
            return 'A'
    for b in range(6, 10):
        if x == b:
            return 'B'
    for c in range(11, 15):
        if x == c:
            return 'C'


def c_test8(x):
    return _c_test8(x)
%timeit c_test8(4)

90.5 ns ± 0.456 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

広告
カテゴリー: 未分類 パーマリンク

頭の体操 への1件のフィードバック

  1. ピンバック: 細々と | 粉末@それは風のように (日記)

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中