Python으로 지루한 작업 자동화의 동전 뒤집기 행진
질문이 너무 많이 반복되면 미리 사과드립니다. 이것은 Automate the Boring Stuff with Python의 연습 과제입니다. 간단히 말해서,이 작업은 100 개의 동전 던지기에서 6 개의 '머리'또는 '꼬리'의 연속이 있는지 확인하는 실험을 수행하는 코드를 작성하고이를 10,000 번 복제하고 성공률의 백분율을 제공하는 것입니다.
코드를 작성할 때 미리 정해진 여러 실험 (제 경우 샘플은 100 만 동전 던지기)에서 코드를 모든 행진에 적용 할 수 있도록 변경하려고했습니다. 나는 또한 그 실험에서 가능한 가장 긴 행진을 찾으려고 노력했다.
또한 댓글이 몹시 장황한 것에 대해 미리 사과하고 싶습니다.
import random, copy, time
def torai(seq,pop): # seq is for #=streak, pop is for total sample/population/experiment
# Creating a random chance of heads and tails
tosses = []
for i in range(pop):
tosses.append(random.randint(1,2)) # 1 and 2 for head and tail, and vice versa
# Defining initial values for the main loop
streak = 0 # Iterated streak
curlongstr = 0 # Current longest streak
longeststr = 0 # Longest streak evaluated
peak = [] # Record local streaks from 'tosses' list
# The main loop
for i in range(len(tosses)): # Looping based on list indexes
if i == 0: # Conditional for preventing tosses[0] == tosses[-1]
continue
elif tosses[i] == tosses[i-1]: # Conditional for checking if an i element has the same value as the previous element value, i-1
streak += 1 # Adding tally mark if the line above is fulfilled
if i == len(tosses)-1: # A nested conditional for adding the last tally mark from 'tosses' into the overall list of steaks 'peak', see lines 27-33
peak.append(streak)
elif tosses[i] != tosses[i-1]: # Conditional for checking if an i element value is different than the previous element value, i-1
curlongstr = copy.copy(streak) # Creating a variable by returning a copy of streak before it resets to 0, see line 31
if curlongstr > longeststr: # A nested conditional for comparing the current longest streak and the longest streak that has happened when looping the 'tosses' list
longeststr = curlongstr
streak = 0 # This is where streaks ended and then resets to 0, so before that, the value of the streak is copied first, see line 28
if curlongstr > streak: # After streak is reset to 0, the value of current long streak is compared to 0, so that we create a list of streaks from 'tosses' list
peak.append(curlongstr)
truepeak = []
for i in peak: # Example: a 2-streak is equal to either [1,1,1] or [2,2,2], a 4-streak is either [1,1,1,1,1] or [2,2,2,2,2]
truepeak.append(i+1)
apr = []
# Loop for finding how many #-streaks happened
for i in truepeak:
if i == seq:
apr.append(i)
print('%s-streak count: ' %seq, len(apr)) # Total of #-streaks happened in 'tosses' list
print('%s-streak prob (percent): ' %seq, (len(apr)/pop)*100) # Calculating probability if how many #-streak happened in given n times tosses
print('longest streak: ',longeststr + 1) # Similar reason as line 36
print('process time: ',time.process_time(), 'second\n')
return (len(apr)/pop)*100
x = torai(2,1000000)
y = torai(6,1000000)
z = torai(10,1000000)
print(x, y, z)
샘플을 1000 만 동전 던지기로 늘리려 고했습니다. 그러나 프로그램은 함수가 호출 될 때마다 9-10 더 느리게 실행됩니다.
내 요청은 결과 (n-streak 확률)가 올바른지 여부를 누구나 확인할 수 있으며 코드 및 처리 시간을 단축 할 수있는 방법이 있습니까?
답변
버그
torai(1, 10000)
이것은 50 %
개별 카운트이기 때문에 주위 에 무언가를 인쇄해야합니다 . 그러나 대신 인쇄
1-streak count: 0
1-streak prob (percent): 0.0
longest streak: 19
process time: 0.046875 second
너무 많은 댓글을 피하세요
코드에 주석이 너무 많아서 코드가 불필요하게 복잡해 보입니다. 내가 추천하는 것은 독 스트링 의 사용법입니다 . IMO 여기서는 그다지 중요하지 않지만 백만 개의 댓글보다 낫습니다.
def torai(seq,pop):
tosses = []
for i in range(pop):
tosses.append(random.randint(1,2))
streak = 0
curlongstr = 0
longeststr = 0
peak = []
for i in range(len(tosses)):
if i == 0:
continue
elif tosses[i] == tosses[i-1]:
streak += 1
if i == len(tosses)-1:
peak.append(streak)
elif tosses[i] != tosses[i-1]:
curlongstr = copy.copy(streak)
if curlongstr > longeststr:
longeststr = curlongstr
streak = 0
if curlongstr > streak:
peak.append(curlongstr)
truepeak = []
for i in peak:
truepeak.append(i+1)
apr = []
for i in truepeak:
if i == seq:
apr.append(i)
print('%s-streak count: ' %seq, len(apr))
print('%s-streak prob (percent): ' %seq, (len(apr)/pop)*100)
print('longest streak: ',longeststr + 1)
print('process time: ',time.process_time(), 'second\n')
return (len(apr)/pop)*100
단순화 # 1
for i in range(len(tosses)):
if i == 0:
continue
첫 번째 요소를 건너 뛰고 싶은 것이 분명합니다. 이 경우 시작 지점을 지정할 수 있습니다.range()
for i in range(1, len(tosses)):
단순화 # 2
for i in range(pop):
tosses.append(random.randint(1,2))
이것은 불변의 시퀀스가 될 것이기 때문에 생성기와 함께 tuple을 사용하십시오.
tosses = tuple(random.randint(1, 2) for _ in range(pop)
단순화 # 3
if curlongstr > longeststr:
longeststr = curlongstr
당신의 상태는 간단합니다. 새 값은 항상 둘 중 더 큽니다.
그냥 max()
함수를 사용하십시오.
longeststr = max(longeststr, curlongstr)
단순화 # 4
truepeak = []
for i in peak:
truepeak.append(i+1)
완전히 새로운 목록을 만들고 peak
상수가 1
추가 된 것을 제외하고 는 정확히 동일한 요소로 채워야 합니다. 매우 비효율적입니다. +1
처음부터 값을 추가 하거나 +1
필요한 경우 사용하십시오 .
for i in peak:
if i + 1 == seq:
apr.append(i + 1)
그러나 다시 말하지만, 당신이 할 일은 apr
길이를 얻는 것이므로 카운터를 유지하기 만하면 너무 많은 목록을 유지하는 데 전혀 의미가 없습니다. 또한 유지 관리 할 필요가 없습니다.peak
이동하면서 토스 계산
이전 루프를 모두 제거한 후에도 2 개가 남아 있습니다. 하나는 토스를 계산하기위한 것이고 다른 하나는 그것들을 계산하기 위해 그것들을 통과합니다. 내가 제안하는 것은 한 번만 검토하고 두 가지를 추적하는 것입니다. 현재 플립 및 이전 플립
def torai(seq, iterations ):
total_streaks = 0
previous_flip = random.randint(1, 2)
for _ in range(1, iterations):
current_flip = random.randint(1, 2)
if current_flip == previous_flip:
total_streaks += 1
# other calculations
current_flip = previous_flip
print(f"Total streaks: {total_streaks}")
내 독해력과 수학은 유아와 동등하다. 그래서 방금 배운 것처럼 위의 코드를 수정하고 싶습니다. 왜냐하면 # -streak 100 만 토스를 찾는 것은 100 번 토스가 천번 복제 된 것과는 다릅니다 (또한 Aryan의 답변에서 입력을 적용 함).
아래 코드 는 여러 번 던질 때 최소 # 쌍 의 확률 만 계산합니다 .
import random, copy, time, sys
def oddstreak(strk,totoss,sample):
'''
Return the probability of AT LEAST #-streak in a number of tosses
and a predetermined sample value.
Parameter:
strk (int) : streak value
totoss (int) : number of tosses
sample (int) : number of repetition
Return:
probability (float) : probability of #-streak(s)
For sanity checking, just uncomment every print list variable and set
'totoss' and 'sample' to a smaller value, i.e., 50 and 3.
'''
if int(strk) == 1:
sys.exit('2-steak is a minimum value. Enter value greater than 1')
streakchecker = list()
for i in range(sample):
tosses = tuple(random.randint(1, 2) for _ in range(totoss))
#print(tosses)
localstreak = 0
streak = 0
sancheck = list()
for i in range(1,len(tosses)):
if tosses[i] == tosses[i-1]:
streak += 1
if i == len(tosses)-1:
sancheck.append(streak)
elif tosses[i] != tosses[i-1]:
localstreak = copy.copy(streak)
streak = 0
if localstreak > streak:
sancheck.append(localstreak)
#print('sancheck: ', sancheck)
for n in sancheck:
if n != (int(strk) - 1):
continue
elif n == (int(strk) - 1):
streakchecker.append(1)
break
#print(streakchecker)
probability = sum(streakchecker)/sample*100
print('Percentage of appeareance of AT LEAST a %s-streak (H or T): %g percent' % (strk, probability))
print('Process time: ',time.process_time(), 'second\n')
return probability
oddstreak(6,100,100000)
결과는 다음과 같습니다.
Percentage of the appearance of AT LEAST a 6-streak (H or T) in a number of coin tosses: 54.542 percent
Process time: 11.0 second
이 새로운 코드에 대한 모든 입력은 대단히 감사합니다. 감사합니다 :)