Python으로 지루한 작업 자동화의 동전 뒤집기 행진

Nov 18 2020

질문이 너무 많이 반복되면 미리 사과드립니다. 이것은 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 확률)가 올바른지 여부를 누구나 확인할 수 있으며 코드 및 처리 시간을 단축 할 수있는 방법이 있습니까?

답변

6 AryanParekh Nov 18 2020 at 17:04

버그

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}")
yfr Nov 19 2020 at 17:58

내 독해력과 수학은 유아와 동등하다. 그래서 방금 배운 것처럼 위의 코드를 수정하고 싶습니다. 왜냐하면 # -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

이 새로운 코드에 대한 모든 입력은 대단히 감사합니다. 감사합니다 :)