Numpy: BUG : np.vectorize () ν•¨μˆ˜λŠ” 첫 번째 μš”μ†Œμ—μ„œ 두 번 μž‘λ™ν•©λ‹ˆλ‹€ (ν•¨μˆ˜κ°€ λ³€κ²½ κ°€λŠ₯ν•œ 객체λ₯Ό μˆ˜μ •ν•  λ•Œ ν‘œμ‹œλ¨).

에 λ§Œλ“  2017λ…„ 03μ›” 08일  Β·  7μ½”λ©˜νŠΈ  Β·  좜처: numpy/numpy

사전 λͺ©λ‘μ΄ μžˆμŠ΅λ‹ˆλ‹€. np.vectorizeλ₯Ό μ‚¬μš©ν•˜μ—¬ λͺ©λ‘μ˜ 각 사전에 λŒ€ν•œ 사전 μš”μ†Œλ₯Ό μˆ˜μ •ν•˜λŠ” ν•¨μˆ˜λ₯Ό μ μš©ν•˜λ €κ³ ν•©λ‹ˆλ‹€. κ²°κ³ΌλŠ” 벑터화가 첫 번째 μš”μ†Œμ—μ„œ 두 번 μž‘λ™ν•œλ‹€λŠ” 것을 λ³΄μ—¬μ€λ‹ˆλ‹€. 이것은 κ³ μΉ  μˆ˜μžˆλŠ” λ²„κ·Έμž…λ‹ˆκΉŒ? (μ•„λ§ˆλ„ 벑터화가 첫 번째 μš”μ†Œμ˜ μœ ν˜•μ„ κ²€μ‚¬ν•œλ‹€λŠ” 사싀과 관련이 μžˆμŠ΅λ‹ˆκΉŒ?) λ‹€μŒμ€ λͺ‡ 가지 사둀 및 좜λ ₯μž…λ‹ˆλ‹€.

사전 μˆ˜μ •μ΄μ—†λŠ” κ°„λ‹¨ν•œ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€ :

def fcn1(x):
    return x['b']
a = [{'b': 1} for _ in range(3) ]
print(a)
print(np.vectorize(fcn1)(a))
print(a, '\n\n')

μ‚°μΆœ:

[{'b': 1}, {'b': 1}, {'b': 1}]
[1 1 1]
[{'b': 1}, {'b': 1}, {'b': 1}]

이제 사전을 μˆ˜μ •ν•˜κ³  ν•¨μˆ˜κ°€ 첫 번째 μš”μ†Œμ— 두 번 μ μš©λ˜λŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€.

def fcn2(x):
    x['b'] += 1
    return x['b']
a = [{'b': 1} for _ in range(3) ]
print(a)
print(np.vectorize(fcn2)(a))
print(a, '\n\n')

μ‚°μΆœ:

[{'b': 1}, {'b': 1}, {'b': 1}]
[3 2 2]
[{'b': 3}, {'b': 2}, {'b': 2}]  

λ²„κ·Έμ˜ 일관성을 ν™•μΈν•˜λ €λ©΄ λ‹€λ₯Έ μˆ˜μ •μ„ μ‹œλ„ν•˜μ‹­μ‹œμ˜€.

def fcn3(x):
    x['b'] *= 2
    return x['b']
a = [{'b': 1} for _ in range(3) ]
print(a)
print(np.vectorize(fcn3)(a))
print(a, '\n\n')

μ‚°μΆœ:

[{'b': 1}, {'b': 1}, {'b': 1}]
[4 2 2]
[{'b': 4}, {'b': 2}, {'b': 2}]    

μ‹€μ œλ‘œ λ°˜ν™˜ 값을 μ œκ³΅ν•˜μ§€ μ•Šκ³ λ„ λ™μΌν•œ μž‘μ—…μ„ μˆ˜ν–‰ ν•  수 μžˆμŠ΅λ‹ˆλ‹€ (μ‚¬μš© μ‚¬λ‘€μ—μ„œ μ‚¬μš©ν•˜λ €λŠ” λ°©λ²•μž…λ‹ˆλ‹€).

def fcn4(x):
    x['b'] += 1
a = [{'b': 1} for _ in range(3) ]
print(a)
np.vectorize(fcn4)(a)
print(a, '\n\n')

μ‚°μΆœ:

[{'b': 1}, {'b': 1}, {'b': 1}]
[{'b': 3}, {'b': 2}, {'b': 2}]

그건 κ·Έλ ‡κ³ , 길이 3의 λͺ©λ‘μ— λŒ€ν•΄ νŠΉλ³„ν•œ 것은 μ—†μŠ΅λ‹ˆλ‹€. 당신은 그것을 λ³€κ²½ν•  수 있고 두 번 μˆ˜μ •λ˜λŠ” 첫 번째 μš”μ†Œμ˜ λ™μΌν•œ λ™μž‘μ„ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

Numpy 버전 1.11.3κ³Ό 1.12.0을 λͺ¨λ‘ μ‚¬μš©ν•˜μ—¬ λ™μž‘μ„ ν™•μΈν–ˆμŠ΅λ‹ˆλ‹€.

νŽΈμ§‘ν•˜λ‹€:
λ˜ν•œ "첫 번째 μš”μ†Œμ—μ„œ μœ ν˜• ν…ŒμŠ€νŠΈ"문제λ₯Ό ν™•μΈν•˜λŠ” ν•΄κ²° 방법을 μ°Ύμ•˜μŠ΅λ‹ˆλ‹€. otypes 인수λ₯Ό μ§€μ •ν•˜λ©΄ 첫 번째 μš”μ†Œκ°€ 두 번 μ μ€‘λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

def fcn(x):
    x['b'] += 1
    return x['b']
a = [{'b': 1} for _ in range(3)]
print a
print np.vectorize(fcn, otypes=[dict])(a)
print a, '\n\n'

μ‚°μΆœ:

[{'b': 1}, {'b': 1}, {'b': 1}]
[2 2 2]
[{'b': 2}, {'b': 2}, {'b': 2}]
00 - Bug

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

"otypesλ₯Ό μ§€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ 첫 번째 μΈμˆ˜κ°€μžˆλŠ” ν•¨μˆ˜μ— λŒ€ν•œ 호좜이 좜λ ₯ 수λ₯Ό κ²°μ •ν•˜λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€.이 호좜의 κ²°κ³ΌλŠ” ν•¨μˆ˜λ₯Ό 두 번 ν˜ΈμΆœν•˜μ§€ μ•Šλ„λ‘ μΊμ‹œκ°€ True이면 μΊμ‹œλ©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ κ΅¬ν˜„ν•˜λ €λ©΄ μΊμ‹œ, μ›λž˜ ν•¨μˆ˜λ₯Ό λž˜ν•‘ν•΄μ•Ό 후속 호좜 속도가 λŠλ €μ§€λ―€λ‘œ ν•¨μˆ˜κ°€ λΉ„μ‹Ό κ²½μš°μ—λ§Œμ΄ μž‘μ—…μ„ μˆ˜ν–‰ν•˜μ‹­μ‹œμ˜€. "
https://docs.scipy.org/doc/numpy/reference/generated/numpy.vectorize.html

λ”°λΌμ„œ 잘 λ¬Έμ„œν™” 된 λ™μž‘μ΄μ§€λ§Œ 직관적이지 μ•Šμ€ κ²ƒμ²˜λŸΌ λ³΄μž…λ‹ˆλ‹€. λ”°λΌμ„œ 버그 μˆ˜μ •λ³΄λ‹€ κ°œμ„  된 λΆ€λΆ„ 일 수 μžˆμŠ΅λ‹ˆλ‹€.

λͺ¨λ“  7 λŒ“κΈ€

첫 번째 ν•­λͺ© μœ ν˜•μ΄ 문제의 원인인지 ν™•μΈν•˜λŠ” μƒˆλ‘œμš΄ ν…ŒμŠ€νŠΈλ‘œ κ²Œμ‹œλ¬Όμ„ νŽΈμ§‘ν–ˆμŠ΅λ‹ˆλ‹€.

더 κ°„λ‹¨ν•œ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€ :

a = np.array([1, 2, 3])
def f(x):
    print('got', x)
    return x
fv = np.vectorize(f)
y = fv(a)

제곡 :

got 1
got 1
got 2
got 3

"otypesλ₯Ό μ§€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ 첫 번째 μΈμˆ˜κ°€μžˆλŠ” ν•¨μˆ˜μ— λŒ€ν•œ 호좜이 좜λ ₯ 수λ₯Ό κ²°μ •ν•˜λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€.이 호좜의 κ²°κ³ΌλŠ” ν•¨μˆ˜λ₯Ό 두 번 ν˜ΈμΆœν•˜μ§€ μ•Šλ„λ‘ μΊμ‹œκ°€ True이면 μΊμ‹œλ©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ κ΅¬ν˜„ν•˜λ €λ©΄ μΊμ‹œ, μ›λž˜ ν•¨μˆ˜λ₯Ό λž˜ν•‘ν•΄μ•Ό 후속 호좜 속도가 λŠλ €μ§€λ―€λ‘œ ν•¨μˆ˜κ°€ λΉ„μ‹Ό κ²½μš°μ—λ§Œμ΄ μž‘μ—…μ„ μˆ˜ν–‰ν•˜μ‹­μ‹œμ˜€. "
https://docs.scipy.org/doc/numpy/reference/generated/numpy.vectorize.html

λ”°λΌμ„œ 잘 λ¬Έμ„œν™” 된 λ™μž‘μ΄μ§€λ§Œ 직관적이지 μ•Šμ€ κ²ƒμ²˜λŸΌ λ³΄μž…λ‹ˆλ‹€. λ”°λΌμ„œ 버그 μˆ˜μ •λ³΄λ‹€ κ°œμ„  된 λΆ€λΆ„ 일 수 μžˆμŠ΅λ‹ˆλ‹€.

μ•„, λΆ„λͺ…νžˆ λͺ¨λ“  λ¬Έμ„œλ₯Ό μΆ©λΆ„νžˆ 읽지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€. 이쀑 호좜 λ¬Έμ œλŠ” ν•΄κ²°λ˜μ§€λ§Œ μ‹€ν–‰ 속도가 λŠλ €μ§‘λ‹ˆλ‹€. λ”°λΌμ„œ μ„±λŠ₯을 μœ μ§€ν•˜λ©΄μ„œ 이쀑 ν˜ΈμΆœμ„ 방지 ν•  μˆ˜μžˆλŠ” 방법이 μ—†λ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄ vectorize 클래슀 ν•¨μˆ˜ _get_ufunc_and_otypes() numpy/lib/function_base.py μ—μ„œ λ‹€μŒ 쀄을 μˆ˜μ •ν•  수 μžˆλ‹€κ³  μˆœμ§„ν•˜κ²Œ μƒκ°ν•©λ‹ˆλ‹€.

inputs = [arg.flat[0] for arg in args]
outputs = func(*inputs)

에:

#earlier
import copy

...

inputs = copy.deepcopy([arg.flat[0] for arg in args])
outputs = func(*inputs)

그리고 μΊμ‹œλ₯Ό μ‚¬μš©ν•˜κ±°λ‚˜ otype을 지정할 ν•„μš”λŠ” μ—†μ§€λ§Œ μ‹€μ œ λ³€κ²½ κ°€λŠ₯ν•œ μš”μ†Œλ₯Ό 두 번 λˆ„λ₯΄λŠ” 것은 ν”Όν•  수 μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λ‚˜λŠ” 캐싱과 비ꡐ할 λ•Œ μ–Όλ§ˆλ‚˜ λ§Žμ€ μ„±λŠ₯ μ €ν•˜λ₯Ό κ°€μ Έμ˜¬ 지 λ¬΄μ§€ν•©λ‹ˆλ‹€.

캐싱 λ™μž‘μ΄ κ°’ λΉ„μ‹Ό ν•¨μˆ˜ μ‹€ν–‰ μ‹œκ°„μ„ 염두에두고 μ„€κ³„λ˜μ—ˆλ‹€λŠ” λŠλ‚Œμ„ λ°›κ³  μžˆμŠ΅λ‹ˆλ‹€. ν•¨μˆ˜κ°€ κ°€λ³€ 객체λ₯Ό μˆ˜μ •ν•˜λŠ” κ²½μš°λŠ” μƒκ°ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. κΈ΄ ν•¨μˆ˜ μ‹€ν–‰ μ‹œκ°„μ„ 염두에 λ‘” μΊμ‹±μ˜ μ„±λŠ₯ μ €ν•˜μ—†μ΄ λ³€κ²½ κ°€λŠ₯ν•œ 객체 μˆ˜μ •μ„ 수용 ν•  수 μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

맀우 큰 객체의 배열에 λŒ€ν•œ 벑터화 된 μž‘μ—…μ˜ 경우 μ‹€μ œλ‘œ ν•¨μˆ˜λ₯Ό μ μš©ν•˜λŠ” 데 λ“œλŠ” λΉ„μš©λ³΄λ‹€ 첫 번째 μš”μ†Œμ˜ κΉŠμ€ 볡사본을 λ§Œλ“œλŠ” 것이 계산 집약적 일 수 μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. λ”°λΌμ„œ μ‚¬μš©μžκ°€ otype μ§€μ •ν•˜μ§€ μ•Šμ€ 경우 ν•΄λ‹Ή κΈ°λŠ₯을 μ‚¬μš©ν•˜λŠ” 것이 쒋을 수 μžˆμ§€λ§Œ 큰 배열에 λŒ€ν•΄ otype λ₯Ό μ§€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ μ„±λŠ₯이 μ €ν•˜ 될 수 μžˆλ‹€κ³  λ¬Έμ„œμ—μ„œ λ§ν•©λ‹ˆλ‹€. 사물. @ eric-wieser μ–΄λ–»κ²Œ μƒκ°ν•˜μ„Έμš”?

copy.deepcopy() λŠ” λ§Žμ€ μž…λ ₯μ—μ„œ μ•ˆμ „ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ λΆˆν–‰νžˆλ„ μ‹€ν–‰ κ°€λŠ₯ν•œ μ˜΅μ…˜μ΄ μ•„λ‹™λ‹ˆλ‹€.

이 문제λ₯Ό ν•΄κ²°ν•˜λŠ” μœ μΌν•œ 방법은 vectorize 의 μ½”μ–΄λ₯Ό λ‹€μ‹œ μž‘μ„±ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. ν˜„μž¬ numpy.frompyfunc λ₯Ό μ‚¬μš©ν•˜μ—¬ μ‹€μ œλ‘œ numpy ufuncλ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. np.apply_along_axis μ‚¬μš©ν•˜λŠ” 것과 μœ μ‚¬ν•œ λŒ€μ²΄ λ‚΄λΆ€ 루프λ₯Ό λ§Œλ“€μ–΄μ•Όν•©λ‹ˆλ‹€. λΆˆν–‰νžˆλ„ μ„±λŠ₯ μ €ν•˜λ₯Ό λ°©μ§€ν•˜λ €λ©΄ Cμ—μ„œ 루프λ₯Ό μˆ˜ν–‰ν•΄μ•Όν•œλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€ ( frompyfunc κ°€ κ΅¬μ„±ν•˜λŠ” ufuncμ—μ„œ μˆ˜ν–‰ν•˜λŠ” μž‘μ—…).

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰