成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Python 進(jìn)階之路 (十一) 再立Flag, 社區(qū)最全的itertools深度解析(下)

tomorrowwu / 708人閱讀

摘要:將每一行作為返回,其中是每行中的列名。對(duì)于每一行,都會(huì)生成一個(gè)對(duì)象,其中包含和列中的值。它返回一個(gè)迭代器,是迭代結(jié)果都為的情況。深度解析至此全劇終。

簡(jiǎn)單實(shí)戰(zhàn)

大家好,我又來(lái)了,在經(jīng)過(guò)之前兩篇文章的介紹后相信大家對(duì)itertools的一些常見(jiàn)的好用的方法有了一個(gè)大致的了解,我自己在學(xué)完之后仿照別人的例子進(jìn)行了真實(shí)場(chǎng)景下的模擬練習(xí),今天和大家一起分享,有很多部分還可以?xún)?yōu)化,希望有更好主意和建議的朋友們可以留言哈,讓我們一起進(jìn)步

實(shí)戰(zhàn):分析標(biāo)準(zhǔn)普爾500指數(shù) 數(shù)據(jù)源及目標(biāo)

在這個(gè)例子中,我們首先嘗試使用itertools來(lái)操作大型數(shù)據(jù)集:標(biāo)準(zhǔn)普爾500指數(shù)的歷史每日價(jià)格數(shù)據(jù)。 我會(huì)在這個(gè)部分的最后附上下載鏈接和py文件,這里的數(shù)據(jù)源來(lái)自雅虎財(cái)經(jīng)

目標(biāo): 找到標(biāo)準(zhǔn)普爾500指數(shù)的單日最大收益,最大損失(百分比),和最長(zhǎng)的增長(zhǎng)周期

首先我們手上得到了 SP500.csv ,讓我們對(duì)數(shù)據(jù)有個(gè)大概的印象,前十行的數(shù)據(jù)如下:

Date,Open,High,Low,Close,Adj Close,Volume
1950-01-03,16.660000,16.660000,16.660000,16.660000,16.660000,1260000
1950-01-04,16.850000,16.850000,16.850000,16.850000,16.850000,1890000
1950-01-05,16.930000,16.930000,16.930000,16.930000,16.930000,2550000
1950-01-06,16.980000,16.980000,16.980000,16.980000,16.980000,2010000
1950-01-09,17.080000,17.080000,17.080000,17.080000,17.080000,2520000
1950-01-10,17.030001,17.030001,17.030001,17.030001,17.030001,2160000
1950-01-11,17.090000,17.090000,17.090000,17.090000,17.090000,2630000
1950-01-12,16.760000,16.760000,16.760000,16.760000,16.760000,2970000
1950-01-13,16.670000,16.670000,16.670000,16.670000,16.670000,3330000

為了實(shí)現(xiàn)目標(biāo),具體思路如下:

讀取csv文件,并利用 Adj Close這一列轉(zhuǎn)換為每日百分比變化的序列,代表收益,命名為gain

找到gain這一序列中的最大值和最小值,并且找到對(duì)應(yīng)的日期,當(dāng)然,有可能會(huì)出現(xiàn)對(duì)應(yīng)多個(gè)日期的情況,我們這里選取日期最近的就好。

定義一個(gè)sequence叫做growth_streaks,其中包含了所有 gain中出現(xiàn)的連續(xù)為正值的元素組成的tuple,我們要找到這些tuples中長(zhǎng)度最長(zhǎng)的一個(gè),從而定位其對(duì)應(yīng)的開(kāi)始時(shí)間和結(jié)束時(shí)間,當(dāng)然這里也是一樣,有可能出現(xiàn)最大長(zhǎng)度一樣的的情況,這種情況下,我們還是選擇日期最近的。

這里有關(guān)百分比的計(jì)算公式如下:

分步實(shí)現(xiàn)

首先在這里,我們會(huì)經(jīng)常處理日期,為了方便后續(xù)操作,這里我們引入collections模塊的namedtuple來(lái)實(shí)現(xiàn)對(duì)日期的相關(guān)操作:

from collections import namedtuple


class DataPoint(namedtuple("DataPoint", ["date", "value"])):
    __slots__ = ()

    def __le__(self, other):
        return self.value <= other.value

    def __lt__(self, other):
        return self.value < other.value

    def __gt__(self, other):
        return self.value > other.value

這里有很多小技巧,之后我會(huì)再系統(tǒng)的開(kāi)一個(gè)Python OOP筆記,會(huì)為大家都講到,這里面涉及的小知識(shí)點(diǎn)如下:

slots :這是一個(gè)節(jié)省變量?jī)?nèi)存的好東西,__slot__后面一般都是跟class中 init 方法里面用到的變量,好處在于能夠大量節(jié)省內(nèi)存

namedtuple:可以實(shí)現(xiàn)類(lèi)似屬性一樣調(diào)用tuple里面的元素,我在collections里面詳細(xì)說(shuō)過(guò),大家可以看看:Python 進(jìn)階之路 (七) 隱藏的神奇寶藏:探秘Collections

le:運(yùn)算符重載,可以得到class中一個(gè)變量的長(zhǎng)度,必須是整數(shù),也就是說(shuō)如果傳入的是list,dict,tuple,set這些一定沒(méi)有問(wèn)題,因?yàn)檫@些序列的長(zhǎng)度一定是整數(shù),這里面?zhèn)鬟f的是tuple()

lt:運(yùn)算符重載(less than ):可以實(shí)現(xiàn)利用 < 比較一個(gè)class的不同對(duì)象中的值大小的比較

gt:運(yùn)算符重載(greater than):可以實(shí)現(xiàn)利用 > 比較一個(gè)class的不同對(duì)象中的值大小的比較

下面為了喚醒大家的記憶,我這里快速舉一個(gè)有關(guān)于namedtuple,le,lt,gt的小栗子:

from collections import namedtuple
class Person(namedtuple("person", ["name", "age","city","job"])):

    def __le__(self):
        return len(self)

    def __lt__(self,other):
        return self.age < other.age

    def __gt__(self,other):
        return self.age > other.age


xiaobai = Person("xiaobai", 18, "paris","student")
laobai = Person("Walter White",52, "albuquerque","cook")


print("Infomation for first person: ", xiaobai)     # 顯示全部信息
print("Age of second person is: ", laobai.age)    # 根據(jù)name得到tuple的數(shù)據(jù)
print(len(xiaobai))
print(xiaobai > laobai)
print(xiaobai < laobai)


Out: Infomation for first person:  Person(name="xiaobai", age=18, city="paris",job="student")
     Age of second person is:  52
     4
     False
     True

如果大家對(duì)這個(gè)例子中的一些地方還有疑問(wèn),不用擔(dān)心,我會(huì)在下一個(gè)專(zhuān)欄Python OOP學(xué)習(xí)筆記中和大家慢慢說(shuō)的
。好的,現(xiàn)在回到剛才的實(shí)戰(zhàn):

from collections import namedtuple

class DataPoint(namedtuple("DataPoint", ["date", "value"])):
    __slots__ = ()

    def __le__(self, other):
        return self.value <= other.value

    def __lt__(self, other):
        return self.value < other.value

    def __gt__(self, other):
        return self.value > other.value

這里我們的DataPoint類(lèi)有兩個(gè)主要屬性,一個(gè)是datetime類(lèi)型的日期,一個(gè)是當(dāng)天的標(biāo)普500值

接下來(lái)讓我們讀取csv文件,并將每行中的Date和Adj Close列中的值存為DataPoint的對(duì)象,最后把所有的對(duì)象組合為一個(gè)sequence序列:

import csv
from datetime import datetime


def read_prices(csvfile, _strptime=datetime.strptime):
    with open(csvfile) as infile:
        reader = csv.DictReader(infile)
        for row in reader:
            yield DataPoint(date=_strptime(row["Date"], "%Y-%m-%d").date(),
                            value=float(row["Adj Close"]))


prices = tuple(read_prices("SP500.csv"))

read_prices()生成器打開(kāi) SP500.csv 并使用 csv.DictReader()讀取數(shù)據(jù)的每一行。DictReader()將每一行作為 OrderedDict 返回,其中key是每行中的列名。

對(duì)于每一行,read_prices()都會(huì)生成一個(gè)DataPoint對(duì)象,其中包含“Date”和“Adj Close”列中的值。 最后,完整的數(shù)據(jù)點(diǎn)序列作為元組提交給內(nèi)存并存儲(chǔ)在prices變量中

Ps: Ordereddict是我在collections中漏掉的知識(shí)點(diǎn),我馬上會(huì)補(bǔ)上,大家可以隨時(shí)收藏Python 進(jìn)階之路 (七) 隱藏的神奇寶藏:探秘Collections,我會(huì)繼續(xù)更新

接下來(lái)我們要把prices這個(gè)轉(zhuǎn)變?yōu)楸磉_(dá)每日價(jià)格變化百分比的序列,利用的公式就是剛才提到的,如果忘了的朋友可以往回翻~

gains = tuple(DataPoint(day.date, 100*(day.value/prev_day.value - 1.))
                for day, prev_day in zip(prices[1:], prices))

為了得到標(biāo)普500單日最大漲幅,我們可以用一下方法:

max_gain = DataPoint(None, 0)
for data_point in gains:
    max_gain = max(data_point, max_gain)

print(max_gain)   # DataPoint(date="2008-10-28", value=11.58)

我們可以把這個(gè)方法用之前提到過(guò)的reduce簡(jiǎn)化一下:

import functools as ft

max_gain = ft.reduce(max, gains)

print(max_gain)  # DataPoint(date="2008-10-28", value=11.58)

這里有關(guān)reduce 和 lambda的用法,我們可以通過(guò)一個(gè)小栗子來(lái)回憶一下:

import functools as ft
x = ft.reduce(lambda x,y:x+y,[1, 2, 3, 4, 5])
print(x)

Out: 15

當(dāng)然,如果求和在實(shí)際場(chǎng)景直接用sum就好,這里只是為了讓大家有個(gè)印象,如果回憶不起來(lái)的老鐵們也沒(méi)有關(guān)系,輕輕點(diǎn)擊以下鏈接立刻重溫:

Python 進(jìn)階之路 (五) map, filter, reduce, zip 一網(wǎng)打盡

Python 進(jìn)階之路 (六) 九淺一深 lambda,陳獨(dú)秀你給我坐下!

好了,書(shū)規(guī)正傳,我們發(fā)現(xiàn)用reduce改進(jìn)了for循環(huán)后得到了同樣的結(jié)果,單日最大漲幅的日期也一樣,但是這里需要注意的是reduce和剛才的for循環(huán)完全不是一回事

我們可以想象一下,假如CSV文件中的數(shù)據(jù)每天都是跌的話(huà)。 max_gain最后到底是多少?

在 for 循環(huán)中,首先設(shè)置max_gain = DataPoint(None,0),因此如果沒(méi)有漲幅,則最終的max_gain值將是此空 DataPoint 對(duì)象。但是,reduce()解決方案會(huì)返回最小的單日跌幅,這不是我們想要的,可能會(huì)引入一個(gè)難以找到的bug

這就是itertools可以幫助到我們的地方。 itertools.filterfalse()函數(shù)有兩個(gè)參數(shù):一個(gè)返回True或False的函數(shù),和一個(gè)可迭代的輸入。它返回一個(gè)迭代器,是迭代結(jié)果都為False的情況。這里是個(gè)小栗子:

import itertools as it
only_positives = it.filterfalse(lambda x: x <= 0, [0, 1, -1, 2, -2])
print(list(only_positives))


Out:[1, 2]

所以現(xiàn)在我們可以用 itertools.filterfalse()去除掉gains中那些小于0或者為負(fù)數(shù)的值,這樣reduce會(huì)僅僅作用在我們想要的正收益上:

max_gain = ft.reduce(max, it.filterfalse(lambda p: p <= 0, gains))

這里我們默認(rèn)為gains中一定存在大于0的值,這也是事實(shí),但是如果假設(shè)gains中沒(méi)有的話(huà),我們會(huì)報(bào)錯(cuò),因此在使用itertools.filterfalse()的實(shí)際場(chǎng)景中要注意到這一點(diǎn)。

針對(duì)這種情況,可能你想到的應(yīng)對(duì)方案是在合適的情況下添加TryExpect捕獲錯(cuò)誤,但是reduce有個(gè)更好的解決方案,reuce里面可以傳遞第三個(gè)參數(shù),用做reduce返回結(jié)果不存在時(shí)的默認(rèn)值,這一點(diǎn)和字典的get方法有異曲同工之妙,如果對(duì)get有疑問(wèn)的朋友可以回顧我之前的文章:Python 進(jìn)階之路 (二) Dict 進(jìn)階寶典,初二快樂(lè)!,還是看一個(gè)小栗子:

>>> ft.reduce(max, it.filterfalse(lambda x: x <= 0, [-1, -2, -3]), 0)
0

這回很好理解了,因此我們應(yīng)用到我們標(biāo)準(zhǔn)普爾指數(shù)的實(shí)戰(zhàn)上:

zdp = DataPoint(None, 0)  # zero DataPoint
max_gain = ft.reduce(max, it.filterfalse(lambda p: p.value <= 0, diffs), zdp)

同理,對(duì)于標(biāo)普500單日最大跌幅我們也照貓畫(huà)虎:

max_loss = ft.reduce(min, it.filterfalse(lambda p: p.value > 0, gains), zdp)

print(max_loss)  # DataPoint(date="2018-02-08", value=-20.47)

根據(jù)我們的數(shù)據(jù)源是2018年2月8號(hào)那一天,我沒(méi)有谷歌查詢(xún)那一天發(fā)生了什么,大家感興趣可以看看哈,但是應(yīng)該是沒(méi)有問(wèn)題的,因?yàn)閿?shù)據(jù)源來(lái)自雅虎財(cái)經(jīng)

現(xiàn)在我們已經(jīng)得到了標(biāo)普500歷史上的單日最大漲跌的日期,我們接下來(lái)要找到它的最長(zhǎng)時(shí)間段,其實(shí)這個(gè)問(wèn)題等同于在gains序列中找到最長(zhǎng)的連續(xù)為正數(shù)的點(diǎn)的集合,itertools.takewhile()和itertools.dropwhile()函數(shù)非常適合處理這種情況。

itertools.takewhile()接受兩個(gè)參數(shù),一個(gè)為判斷的條件,一個(gè)為可迭代的序列,會(huì)返回第一個(gè)判斷結(jié)果為False時(shí)之前的迭代過(guò)的所有元素,下面的小栗子很好的解釋了這一點(diǎn)

it.takewhile(lambda x: x < 3, [0, 1, 2, 3, 4])  # 0, 1, 2

itertools.dropwhile() 則恰恰相反:

it.dropwhile(lambda x: x < 3, [0, 1, 2, 3, 4])  # 3, 4

因此我們可以創(chuàng)建一下方法來(lái)實(shí)現(xiàn)在gains中找到連續(xù)為正數(shù)的序列:

def consecutive_positives(sequence, zero=0):
    def _consecutives():
        for itr in it.repeat(iter(sequence)):
            yield tuple(it.takewhile(lambda p: p > zero,
                                     it.dropwhile(lambda p: p <= zero, itr)))
    return it.takewhile(lambda t: len(t), _consecutives())
    
growth_streaks = consecutive_positives(gains, zero=DataPoint(None, 0))
longest_streak = ft.reduce(lambda x, y: x if len(x) > len(y) else y,
                           growth_streaks)

最后讓我們看一下完整的代碼:

from collections import namedtuple
import csv
from datetime import datetime
import itertools as it
import functools as ft


class DataPoint(namedtuple("DataPoint", ["date", "value"])):
    __slots__ = ()

    def __le__(self, other):
        return self.value <= other.value

    def __lt__(self, other):
        return self.value < other.value

    def __gt__(self, other):
        return self.value > other.value


def consecutive_positives(sequence, zero=0):
    def _consecutives():
        for itr in it.repeat(iter(sequence)):
            yield tuple(it.takewhile(lambda p: p > zero,
                                     it.dropwhile(lambda p: p <= zero, itr)))
    return it.takewhile(lambda t: len(t), _consecutives())


def read_prices(csvfile, _strptime=datetime.strptime):
    with open(csvfile) as infile:
        reader = csv.DictReader(infile)
        for row in reader:
            yield DataPoint(date=_strptime(row["Date"], "%Y-%m-%d").date(),
                            value=float(row["Adj Close"]))


# Read prices and calculate daily percent change.
prices = tuple(read_prices("SP500.csv"))
gains = tuple(DataPoint(day.date, 100*(day.value/prev_day.value - 1.))
              for day, prev_day in zip(prices[1:], prices))

# Find maximum daily gain/loss.
zdp = DataPoint(None, 0)  # zero DataPoint
max_gain = ft.reduce(max, it.filterfalse(lambda p: p.value <= zdp, gains))
max_loss = ft.reduce(min, it.filterfalse(lambda p: p.value > zdp, gains), zdp)


# Find longest growth streak.
growth_streaks = consecutive_positives(gains, zero=DataPoint(None, 0))
longest_streak = ft.reduce(lambda x, y: x if len(x) > len(y) else y,
                           growth_streaks)

# Display results.
print("Max gain: {1:.2f}% on {0}".format(*max_gain))
print("Max loss: {1:.2f}% on {0}".format(*max_loss))

print("Longest growth streak: {num_days} days ({first} to {last})".format(
    num_days=len(longest_streak),
    first=longest_streak[0].date,
    last=longest_streak[-1].date
))

最終結(jié)果如下:

Max gain: 11.58% on 2008-10-13
Max loss: -20.47% on 1987-10-19
Longest growth streak: 14 days (1971-03-26 to 1971-04-15)

數(shù)據(jù)源可以點(diǎn)擊這里下載

總結(jié)

這次我為大家梳理一個(gè)利用itertools進(jìn)行了簡(jiǎn)單實(shí)戰(zhàn)的小栗子,這里我們旨在多深入了解itertools,但是真實(shí)的生活中,遇到這種問(wèn)題,哪有這么麻煩,一個(gè)pandas包就搞定了,我以后會(huì)和大家分享和pandas有關(guān)的知識(shí),這一次接連三期的itertools總結(jié)希望大家喜歡。

itertools深度解析至此全劇終。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/43247.html

相關(guān)文章

  • Python 進(jìn)階之路 (十) 再立Flag, 社區(qū)最全itertools深度解析(中)

    前情回顧 大家好,我又回來(lái)了。今天我會(huì)繼續(xù)和大家分享itertools這個(gè)神奇的自帶庫(kù),首先,讓我們回顧一下上一期結(jié)尾的時(shí)候我們講到的3個(gè)方法: combinations() combinations_with_replacement() permutations() 讓我們對(duì)這3個(gè)在排列組合中經(jīng)常會(huì)使用到的函數(shù)做個(gè)總結(jié) combinations() 基礎(chǔ)概念 模板:combinations...

    LMou 評(píng)論0 收藏0
  • Python 進(jìn)階之路 (九) 再立Flag, 社區(qū)最全itertools深度解析(上)

    摘要:例如,以下對(duì)兩個(gè)的相應(yīng)元素求和這個(gè)例子很好的解釋了如何構(gòu)建中所謂的迭代器代數(shù)的函數(shù)的含義。為簡(jiǎn)單起見(jiàn),假設(shè)輸入的長(zhǎng)度可被整除。接受兩個(gè)參數(shù)一個(gè)可迭代的正整數(shù)最終會(huì)在中個(gè)元素的所有組合的元組上產(chǎn)生一個(gè)迭代器。 前言 大家好,今天想和大家分享一下我的itertools學(xué)習(xí)體驗(yàn)及心得,itertools是一個(gè)Python的自帶庫(kù),內(nèi)含多種非常實(shí)用的方法,我簡(jiǎn)單學(xué)習(xí)了一下,發(fā)現(xiàn)可以大大提升工作...

    tuantuan 評(píng)論0 收藏0
  • Python 進(jìn)階之路 (四) 先立Flag, 社區(qū)最全Set用法集錦

    摘要:與上面的操作類(lèi)似,可以使用多種運(yùn)算符和方法來(lái)更改集合的內(nèi)容。通過(guò)修改集合元素方法運(yùn)算符用法通過(guò)修改集合和作用是向集合中添加中所有不存在的元素。 Set是什么 大家好,恰逢初五迎財(cái)神,先預(yù)祝大家新年財(cái)源滾滾!!在上一期詳解tuple元組的用法后,今天我們來(lái)看Python里面最后一種常見(jiàn)的數(shù)據(jù)類(lèi)型:集合(Set) 與dict類(lèi)似,set也是一組key的集合,但不存儲(chǔ)value。由于key不...

    nodejh 評(píng)論0 收藏0
  • Python 進(jìn)階之路 (八) 最用心推導(dǎo)式詳解 (附簡(jiǎn)單實(shí)戰(zhàn)及源碼)

    摘要:什么是推導(dǎo)式大家好,今天為大家?guī)?lái)問(wèn)我最喜歡的推導(dǎo)式使用指南,讓我們先來(lái)看看定義推導(dǎo)式是的一種獨(dú)有特性,推導(dǎo)式是可以從一個(gè)數(shù)據(jù)序列構(gòu)建另一個(gè)新的數(shù)據(jù)序列的結(jié)構(gòu)體。 什么是推導(dǎo)式 大家好,今天為大家?guī)?lái)問(wèn)我最喜歡的Python推導(dǎo)式使用指南,讓我們先來(lái)看看定義~ 推導(dǎo)式(comprehensions)是Python的一種獨(dú)有特性,推導(dǎo)式是可以從一個(gè)數(shù)據(jù)序列構(gòu)建另一個(gè)新的數(shù)據(jù)序列的結(jié)構(gòu)體。...

    hufeng 評(píng)論0 收藏0
  • 從小白程序員一路晉升為大廠(chǎng)高級(jí)技術(shù)專(zhuān)家我看過(guò)哪些書(shū)籍?(建議收藏)

    摘要:大家好,我是冰河有句話(huà)叫做投資啥都不如投資自己的回報(bào)率高。馬上就十一國(guó)慶假期了,給小伙伴們分享下,從小白程序員到大廠(chǎng)高級(jí)技術(shù)專(zhuān)家我看過(guò)哪些技術(shù)類(lèi)書(shū)籍。 大家好,我是...

    sf_wangchong 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<