<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Pandas 騷操作:如何將運行內(nèi)存占用降低 90%!

          共 16558字,需瀏覽 34分鐘

           ·

          2021-08-30 22:28

          來源:機器之心


          當使用 pandas 操作小規(guī)模數(shù)據(jù)(低于 100 MB)時,性能一般不是問題。而當面對更大規(guī)模的數(shù)據(jù)(100 MB 到數(shù) GB)時,性能問題會讓運行時間變得更漫長,而且會因為內(nèi)存不足導(dǎo)致運行完全失敗。
           
          盡管 Spark 這樣的工具可以處理大型數(shù)據(jù)集(100 GB 到數(shù) TB),但要完全利用它們的能力,往往需要更加昂貴的硬件。而且和 pandas 不同,它們?nèi)鄙儇S富的用于高質(zhì)量數(shù)據(jù)清理、探索和分析的功能集。對于中等規(guī)模的數(shù)據(jù),我們最好能更充分地利用 pandas,而不是換成另一種工具。
           
          在這篇文章中,我們將了解 pandas 的內(nèi)存使用,以及如何只需通過為列選擇合適的數(shù)據(jù)類型就能將 dataframe 的內(nèi)存占用減少近 90%。


          處理棒球比賽日志
           
          我們將處理 130 年之久的美國職業(yè)棒球大聯(lián)盟(MLB)比賽數(shù)據(jù),這些數(shù)據(jù)來自 Retrosheet:http://www.retrosheet.org/gamelogs/index.html。
           
          這些數(shù)據(jù)原來分成了 127 個不同的 CSV 文件,但我們已經(jīng)使用 csvkit 合并了這些數(shù)據(jù),并在第一行增加了列名稱。如果你想下載本文所用的這個數(shù)據(jù)版本,請訪問:https://data.world/dataquest/mlb-game-logs。
           
          讓我們首先導(dǎo)入數(shù)據(jù),并看看其中的前五行:
          import pandas as pd

          gl = pd.read_csv('game_logs.csv')
          gl.head()
          下面我們總結(jié)了一些重要的列,但如果你想了解所有的列,我們也為整個數(shù)據(jù)集創(chuàng)建了一個數(shù)據(jù)詞典:https://data.world/dataquest/mlb-game-logs/workspace/data-dictionary。

          • date - 比賽時間

          • v_name - 客隊名

          • v_league - 客隊聯(lián)盟

          • h_name - 主隊名

          • h_league - 主隊聯(lián)盟

          • v_score - 客隊得分

          • h_score - 主隊得分

          • v_line_score - 客隊每局得分排列,例如:010000(10)00.

          • h_line_score - 主隊每局得分排列,例如:010000(10)0X.

          • park_id - 比賽舉辦的球場名

          • attendance- 比賽觀眾

           
          我們可以使用 DataFrame.info() 方法為我們提供關(guān)于 dataframe 的高層面信息,包括它的大小、數(shù)據(jù)類型的信息和內(nèi)存使用情況。

          默認情況下,pandas 會近似 dataframe 的內(nèi)存用量以節(jié)省時間。因為我們也關(guān)心準確度,所以我們將 memory_usage 參數(shù)設(shè)置為 'deep',以便得到準確的數(shù)字。
          gl.info(memory_usage='deep')
          <class 'pandas.core.frame.DataFrame'>
          RangeIndex:
           171907 entries, 0 to 171906
          Columns: 161 entries, date to acquisition_info
          dtypes: float64(77), int64(6), object(78)
          memory usage: 861.6 MB
          我們可以看到,我們有 171,907 行和 161 列。pandas 會自動為我們檢測數(shù)據(jù)類型,發(fā)現(xiàn)其中有 83 列數(shù)據(jù)是數(shù)值,78 列是 object。object 是指有字符串或包含混合數(shù)據(jù)類型的情況。

          為了更好地理解如何減少內(nèi)存用量,讓我們看看 pandas 是如何將數(shù)據(jù)存儲在內(nèi)存中的。

          dataframe 的內(nèi)部表示
           
          在 pandas 內(nèi)部,同樣數(shù)據(jù)類型的列會組織成同一個值塊(blocks of values)。這里給出了一個示例,說明了 pandas 對我們的 dataframe 的前 12 列的存儲方式。


          你可以看到這些塊并沒有保留原有的列名稱。這是因為這些塊為存儲 dataframe 中的實際值進行了優(yōu)化。pandas 的 BlockManager 類則負責保留行列索引與實際塊之間的映射關(guān)系。它可以作為一個 API 使用,提供了對底層數(shù)據(jù)的訪問。不管我們何時選擇、編輯或刪除這些值,dataframe 類和 BlockManager 類的接口都會將我們的請求翻譯成函數(shù)和方法的調(diào)用。
           
          在 pandas.core.internals 模塊中,每一種類型都有一個專門的類。pandas 使用 ObjectBlock 類來表示包含字符串列的塊,用 FloatBlock 類表示包含浮點數(shù)列的塊。對于表示整型數(shù)和浮點數(shù)這些數(shù)值的塊,pandas 會將這些列組合起來,存儲成 NumPy ndarray。NumPy ndarray 是圍繞 C 語言的數(shù)組構(gòu)建的,其中的值存儲在內(nèi)存的連續(xù)塊中。這種存儲方案使得對值的訪問速度非常快。
           
          因為每種數(shù)據(jù)類型都是分開存儲的,所以我們將檢查不同數(shù)據(jù)類型的內(nèi)存使用情況。首先,我們先來看看各個數(shù)據(jù)類型的平均內(nèi)存用量。
          for dtype in ['float','int','object']:
              selected_dtype = gl.select_dtypes(include=[dtype])
              mean_usage_b = selected_dtype.memory_usage(deep=True).mean()
              mean_usage_mb = mean_usage_b / 1024 ** 2
              print("Average memory usage for {} columns: {:03.2f} MB".format(dtype,mean_usage_mb))
          Average memory usage for float columns: 1.29 MB
          Average memory usage for int columns: 1.12 MB
          Average memory usage for object columns: 9.53 MB
          可以看出,78 個 object 列所使用的內(nèi)存量最大。我們后面再具體談這個問題。首先我們看看能否改進數(shù)值列的內(nèi)存用量。

          理解子類型(subtype)
           
          正如我們前面簡單提到的那樣,pandas 內(nèi)部將數(shù)值表示為 NumPy ndarrays,并將它們存儲在內(nèi)存的連續(xù)塊中。這種存儲模式占用的空間更少,而且也讓我們可以快速訪問這些值。因為 pandas 表示同一類型的每個值時都使用同樣的字節(jié)數(shù),而 NumPy ndarray 可以存儲值的數(shù)量,所以 pandas 可以快速準確地返回一個數(shù)值列所消耗的字節(jié)數(shù)。
           
          pandas 中的許多類型都有多個子類型,這些子類型可以使用更少的字節(jié)來表示每個值。比如說 float 類型就包含 float16、float32 和 float64 子類型。類型名稱中的數(shù)字就代表該類型表示值的位(bit)數(shù)。比如說,我們剛剛列出的子類型就分別使用了 2、4、8、16 個字節(jié)。下面的表格給出了 pandas 中最常用類型的子類型:


          一個 int8 類型的值使用 1 個字節(jié)的存儲空間,可以表示 256(2^8)個二進制數(shù)。這意味著我們可以使用這個子類型來表示從 -128 到 127(包括 0)的所有整數(shù)值。
           
          我們可以使用 numpy.iinfo 類來驗證每個整型數(shù)子類型的最大值和最小值。舉個例子:
          import numpy as np
          int_types = ["uint8""int8""int16"]
          for it in int_types:
              print(np.iinfo(it))
          Machine parameters for uint8
          ---------------------------------------------------------------
          min = 0
          max = 255
          ---------------------------------------------------------------

          Machine parameters for int8
          ---------------------------------------------------------------
          min = -128
          max = 127
          ---------------------------------------------------------------

          Machine parameters for int16
          ---------------------------------------------------------------
          min = -32768
          max = 32767
          ---------------------------------------------------------------
          這里我們可以看到 uint(無符號整型)和 int(有符號整型)之間的差異。這兩種類型都有一樣的存儲能力,但其中一個只保存 0 和正數(shù)。無符號整型讓我們可以更有效地處理只有正數(shù)值的列。
           
          使用子類型優(yōu)化數(shù)值列
           
          我們可以使用函數(shù) pd.to_numeric() 來對我們的數(shù)值類型進行 downcast(向下轉(zhuǎn)型)操作。我們會使用 DataFrame.select_dtypes 來選擇整型列,然后我們會對其數(shù)據(jù)類型進行優(yōu)化,并比較內(nèi)存用量。
          # We're going to be calculating memory usage a lot,
          # so we'll create a function to save us some time!

          def mem_usage(pandas_obj):
              if isinstance(pandas_obj,pd.DataFrame):
                  usage_b = pandas_obj.memory_usage(deep=True).sum()
              else# we assume if not a df it's a series
                  usage_b = pandas_obj.memory_usage(deep=True)
              usage_mb = usage_b / 1024 ** 2 # convert bytes to megabytes
              return "{:03.2f} MB".format(usage_mb)

          gl_int = gl.select_dtypes(include=['int'])
          converted_int = gl_int.apply(pd.to_numeric,downcast='unsigned')

          print(mem_usage(gl_int))
          print(mem_usage(converted_int))

          compare_ints = pd.concat([gl_int.dtypes,converted_int.dtypes],axis=1)
          compare_ints.columns = ['before','after']
          compare_ints.apply(pd.Series.value_counts)
          7.87 MB
          1.48 MB


          我們可以看到內(nèi)存用量從 7.9 MB 下降到了 1.5 MB,降低了 80% 以上。但這對我們原有 dataframe 的影響并不大,因為其中的整型列非常少。
           
          讓我們對其中的浮點型列進行一樣的操作。
          gl_float = gl.select_dtypes(include=['float'])
          converted_float = gl_float.apply(pd.to_numeric,downcast='float')

          print(mem_usage(gl_float))
          print(mem_usage(converted_float))

          compare_floats = pd.concat([gl_float.dtypes,converted_float.dtypes],axis=1)
          compare_floats.columns = ['before','after']
          compare_floats.apply(pd.Series.value_counts)
          100.99 MB
          50.49 MB


          我們可以看到浮點型列的數(shù)據(jù)類型從 float64 變成了 float32,讓內(nèi)存用量降低了 50%。
           
          讓我們?yōu)樵?dataframe 創(chuàng)建一個副本,并用這些優(yōu)化后的列替換原來的列,然后看看我們現(xiàn)在的整體內(nèi)存用量。
          optimized_gl = gl.copy()

          optimized_gl[converted_int.columns] = converted_int
          optimized_gl[converted_float.columns] = converted_float

          print(mem_usage(gl))
          print(mem_usage(optimized_gl))
          861.57 MB
          804.69 MB
          盡管我們極大地減少了數(shù)值列的內(nèi)存用量,但整體的內(nèi)存用量僅減少了 7%。我們的大部分收獲都將來自對 object 類型的優(yōu)化。
           
          在我們開始行動之前,先看看 pandas 中字符串的存儲方式與數(shù)值類型的存儲方式的比較。

          數(shù)值存儲與字符串存儲的比較
           
          object 類型表示使用 Python 字符串對象的值,部分原因是 NumPy 不支持缺失(missing)字符串類型。因為 Python 是一種高級的解釋性語言,它對內(nèi)存中存儲的值沒有細粒度的控制能力。
           
          這一限制導(dǎo)致字符串的存儲方式很碎片化,從而會消耗更多內(nèi)存,而且訪問速度也更慢。object 列中的每個元素實際上都是一個指針,包含了實際值在內(nèi)存中的位置的「地址」。
           
          下面這幅圖給出了以 NumPy 數(shù)據(jù)類型存儲數(shù)值數(shù)據(jù)和使用 Python 內(nèi)置類型存儲字符串數(shù)據(jù)的方式。


          圖片來源:https://jakevdp.github.io/blog/2014/05/09/why-python-is-slow/
           
          在前面的表格中,你可能已經(jīng)注意到 object 類型的內(nèi)存使用是可變的。盡管每個指針僅占用 1 字節(jié)的內(nèi)存,但如果每個字符串在 Python 中都是單獨存儲的,那就會占用實際字符串那么大的空間。我們可以使用 sys.getsizeof() 函數(shù)來證明這一點,首先查看單個的字符串,然后查看 pandas series 中的項。
          from sys import getsizeof

          s1 = 'working out'
          s2 = 'memory usage for'
          s3 = 'strings in python is fun!'
          s4 = 'strings in python is fun!'

          for s in [s1, s2, s3, s4]:
              print(getsizeof(s))
          60
          65
          74
          74
          obj_series = pd.Series(['working out',
                                    'memory usage for',
                                    'strings in python is fun!',
                                    'strings in python is fun!'])
          obj_series.apply(getsizeof)
          0    60
          1    65
          2    74
          3    74
          dtype: int64
          你可以看到,當存儲在 pandas series 時,字符串的大小與用 Python 單獨存儲的字符串的大小是一樣的。
           
          使用 Categoricals 優(yōu)化 object 類型
           
          pandas 在 0.15 版引入了 Categorials。category 類型在底層使用了整型值來表示一個列中的值,而不是使用原始值。pandas 使用一個單獨的映射詞典將這些整型值映射到原始值。只要當一個列包含有限的值的集合時,這種方法就很有用。當我們將一列轉(zhuǎn)換成 category dtype 時,pandas 就使用最節(jié)省空間的 int 子類型來表示該列中的所有不同值。


          為了了解為什么我們可以使用這種類型來減少內(nèi)存用量,讓我們看看我們的 object 類型中每種類型的不同值的數(shù)量。
          gl_obj = gl.select_dtypes(include=['object']).copy()
          gl_obj.describe()

          上圖完整圖像詳見原文

          大概看看就能發(fā)現(xiàn),對于我們整個數(shù)據(jù)集的 172,000 場比賽,其中不同(unique)值的數(shù)量可以說非常少。
           
          為了了解當我們將其轉(zhuǎn)換成 categorical 類型時究竟發(fā)生了什么,我們拿出一個 object 列來看看。我們將使用數(shù)據(jù)集的第二列 day_of_week.
           
          看看上表,可以看到其僅包含 7 個不同的值。我們將使用 .astype() 方法將其轉(zhuǎn)換成 categorical 類型。
          dow = gl_obj.day_of_week
          print(dow.head())

          dow_cat = dow.astype('category')
          print(dow_cat.head())
          0    Thu
          1    Fri
          2    Sat
          3    Mon
          4    Tue
          Name: day_of_week, dtype: object
          0    Thu
          1    Fri
          2    Sat
          3    Mon
          4    Tue
          Name: day_of_week, dtype: category
          Categories (7, object): [Fri, Mon, Sat, Sun, Thu, Tue, Wed]
          如你所見,除了這一列的類型發(fā)生了改變之外,數(shù)據(jù)看起來還是完全一樣。讓我們看看這背后發(fā)生了什么。
           
          在下面的代碼中,我們使用了 Series.cat.codes 屬性來返回 category 類型用來表示每個值的整型值。
          dow_cat.head().cat.codes
          0    4
          1    0
          2    2
          3    1
          4    5
          dtype: int8
          你可以看到每個不同值都被分配了一個整型值,而該列現(xiàn)在的基本數(shù)據(jù)類型是 int8。這一列沒有任何缺失值,但就算有,category 子類型也能處理,只需將其設(shè)置為 -1 即可。
           
          最后,讓我們看看在將這一列轉(zhuǎn)換為 category 類型前后的內(nèi)存用量對比。
          print(mem_usage(dow))
          print(mem_usage(dow_cat))
          9.84 MB
          0.16 MB
          9.8 MB 的內(nèi)存用量減少到了 0.16 MB,減少了 98%!注意,這個特定列可能代表了我們最好的情況之一——即大約 172,000 項卻只有 7 個不同的值。
           
          盡管將所有列都轉(zhuǎn)換成這種類型聽起來很吸引人,但了解其中的取舍也很重要。最大的壞處是無法執(zhí)行數(shù)值計算。如果沒有首先將其轉(zhuǎn)換成數(shù)值 dtype,那么我們就無法對 category 列進行算術(shù)運算,也就是說無法使用 Series.min() 和 Series.max() 等方法。
           
          我們應(yīng)該堅持主要將 category 類型用于不同值的數(shù)量少于值的總數(shù)量的 50% 的 object 列。如果一列中的所有值都是不同的,那么 category 類型所使用的內(nèi)存將會更多。因為這一列不僅要存儲所有的原始字符串值,還要額外存儲它們的整型值代碼。你可以在 pandas 文檔中了解 category 類型的局限性:http://pandas.pydata.org/pandas-docs/stable/categorical.html。
           
          我們將編寫一個循環(huán)函數(shù)來迭代式地檢查每一 object 列中不同值的數(shù)量是否少于 50%;如果是,就將其轉(zhuǎn)換成 category 類型。
          converted_obj = pd.DataFrame()

          for col in gl_obj.columns:
              num_unique_values = len(gl_obj[col].unique())
              num_total_values = len(gl_obj[col])
              if num_unique_values / num_total_values < 0.5:
                  converted_obj.loc[:,col] = gl_obj[col].astype('category')
              else:
                  converted_obj.loc[:,col] = gl_obj[col]
          和之前一樣進行比較:
          print(mem_usage(gl_obj))
          print(mem_usage(converted_obj))

          compare_obj = pd.concat([gl_obj.dtypes,converted_obj.dtypes],axis=1)
          compare_obj.columns = ['before','after']
          compare_obj.apply(pd.Series.value_counts)
          752.72 MB
          51.67 MB
          在這個案例中,所有的 object 列都被轉(zhuǎn)換成了 category 類型,但并非所有數(shù)據(jù)集都是如此,所以你應(yīng)該使用上面的流程進行檢查。
           
          object 列的內(nèi)存用量從 752MB 減少到了 52MB,減少了 93%。讓我們將其與我們 dataframe 的其它部分結(jié)合起來,看看從最初 861MB 的基礎(chǔ)上實現(xiàn)了多少進步。
          optimized_gl[converted_obj.columns] = converted_obj

          mem_usage(optimized_gl)
          '103.64 MB'
          Wow,進展真是不錯!我們還可以執(zhí)行另一項優(yōu)化——如果你記得前面給出的數(shù)據(jù)類型表,你知道還有一個 datetime 類型。這個數(shù)據(jù)集的第一列就可以使用這個類型。
          date = optimized_gl.date
          print(mem_usage(date))
          date.head()
          0.66 MB
          0    18710504
          1    18710505
          2    18710506
          3    18710508
          4    18710509
          Name: date, dtype: uint32
          你可能記得這一列開始是一個整型,現(xiàn)在已經(jīng)優(yōu)化成了 unint32 類型。因此,將其轉(zhuǎn)換成 datetime 類型實際上會讓內(nèi)存用量翻倍,因為 datetime 類型是 64 位的。將其轉(zhuǎn)換成 datetime 類型是有價值的,因為這讓我們可以更好地進行時間序列分析。
           
          pandas.to_datetime() 函數(shù)可以幫我們完成這種轉(zhuǎn)換,使用其 format 參數(shù)將我們的日期數(shù)據(jù)存儲成 YYYY-MM-DD 形式。
          optimized_gl['date'] = pd.to_datetime(date,format='%Y%m%d')

          print(mem_usage(optimized_gl))
          optimized_gl.date.head()
          104.29 MB
          0   1871-05-04
          1   1871-05-05
          2   1871-05-06
          3   1871-05-08
          4   1871-05-09
          Name: date, dtype: datetime64[ns]

          在讀入數(shù)據(jù)的同時選擇類型

           
          現(xiàn)在,我們已經(jīng)探索了減少現(xiàn)有 dataframe 的內(nèi)存占用的方法。通過首先讀入 dataframe,然后在這個過程中迭代以減少內(nèi)存占用,我們了解了每種優(yōu)化方法可以帶來的內(nèi)存減省量。但是正如我們前面提到的一樣,我們往往沒有足夠的內(nèi)存來表示數(shù)據(jù)集中的所有值。如果我們一開始甚至無法創(chuàng)建 dataframe,我們又可以怎樣應(yīng)用節(jié)省內(nèi)存的技術(shù)呢?
           
          幸運的是,我們可以在讀入數(shù)據(jù)的同時指定最優(yōu)的列類型。pandas.read_csv() 函數(shù)有幾個不同的參數(shù)讓我們可以做到這一點。dtype 參數(shù)接受具有(字符串)列名稱作為鍵值(key)以及 NumPy 類型 object 作為值的詞典。
           
          首先,我們可將每一列的最終類型存儲在一個詞典中,其中鍵值表示列名稱,首先移除日期列,因為日期列需要不同的處理方式。
          dtypes = optimized_gl.drop('date',axis=1).dtypes

          dtypes_col = dtypes.index
          dtypes_type = [i.name for i in dtypes.values]

          column_types = dict(zip(dtypes_col, dtypes_type))

          # rather than print all 161 items, we'll
          # sample 10 key/value pairs from the dict
          # and print it nicely using prettyprint

          preview = first2pairs = {key:value for key,value in list(column_types.items())[:10]}
          import pprint
          pp = pp = pprint.PrettyPrinter(indent=4)
          pp.pprint(preview)
          {   'acquisition_info''category',
              'h_caught_stealing''float32',
              'h_player_1_name''category',
              'h_player_9_name''category',
              'v_assists''float32',
              'v_first_catcher_interference''float32',
              'v_grounded_into_double''float32',
              'v_player_1_id''category',
              'v_player_3_id''category',
              'v_player_5_id''category'}
          現(xiàn)在我們可以使用這個詞典了,另外還有幾個參數(shù)可用于按正確的類型讀入日期,而且僅需幾行代碼:
          read_and_optimized = pd.read_csv('game_logs.csv',dtype=column_types,parse_dates=['date'],infer_datetime_format=True)

          print(mem_usage(read_and_optimized))
          read_and_optimized.head()
          104.28 MB
          上圖完整圖像詳見原文

          通過優(yōu)化這些列,我們成功將 pandas 的內(nèi)存占用從 861.6MB 減少到了 104.28MB——減少了驚人的 88%!
           
          分析棒球比賽
           
          現(xiàn)在我們已經(jīng)優(yōu)化好了我們的數(shù)據(jù),我們可以執(zhí)行一些分析了。讓我們先從了解這些比賽的日期分布開始。
          optimized_gl['year'] = optimized_gl.date.dt.year
          games_per_day = optimized_gl.pivot_table(index='year',columns='day_of_week',values='date',aggfunc=len)
          games_per_day = games_per_day.divide(games_per_day.sum(axis=1),axis=0)

          ax = games_per_day.plot(kind='area',stacked='true')
          ax.legend(loc='upper right')
          ax.set_ylim(0,1)
          plt.show()
          我們可以看到在 1920 年代以前,星期日的棒球比賽很少,但在上個世紀后半葉就變得越來越多了。
           
          我們也可以清楚地看到過去 50 年來,比賽的日期分布基本上沒什么大變化了。

          讓我們再看看比賽時長的變化情況:
          game_lengths = optimized_gl.pivot_table(index='year', values='length_minutes')
          game_lengths.reset_index().plot.scatter('year','length_minutes')
          plt.show()
          從 1940 年代以來,棒球比賽的持續(xù)時間越來越長。

          總結(jié)和下一步
           
          我們已經(jīng)了解了 pandas 使用不同數(shù)據(jù)類型的方法,然后我們使用這種知識將一個 pandas dataframe 的內(nèi)存用量減少了近 90%,而且也僅使用了一些簡單的技術(shù):
           
          • 將數(shù)值列向下轉(zhuǎn)換成更高效的類型

          • 將字符串列轉(zhuǎn)換成 categorical 類型


          左手Python,右手Java,升職就業(yè)不愁啦!






          推薦閱讀:

          入門: 最全的零基礎(chǔ)學(xué)Python的問題  | 零基礎(chǔ)學(xué)了8個月的Python  | 實戰(zhàn)項目 |學(xué)Python就是這條捷徑


          干貨:爬取豆瓣短評,電影《后來的我們》 | 38年NBA最佳球員分析 |   從萬眾期待到口碑撲街!唐探3令人失望  | 笑看新倚天屠龍記 | 燈謎答題王 |用Python做個海量小姐姐素描圖 |碟中諜這么火,我用機器學(xué)習(xí)做個迷你推薦系統(tǒng)電影


          趣味:彈球游戲  | 九宮格  | 漂亮的花 | 兩百行Python《天天酷跑》游戲!


          AI: 會做詩的機器人 | 給圖片上色 | 預(yù)測收入 | 碟中諜這么火,我用機器學(xué)習(xí)做個迷你推薦系統(tǒng)電影


          小工具: Pdf轉(zhuǎn)Word,輕松搞定表格和水?。?/a> | 一鍵把html網(wǎng)頁保存為pdf!|  再見PDF提取收費! | 用90行代碼打造最強PDF轉(zhuǎn)換器,word、PPT、excel、markdown、html一鍵轉(zhuǎn)換 | 制作一款釘釘?shù)蛢r機票提示器! |60行代碼做了一個語音壁紙切換器天天看小姐姐!


          年度爆款文案


          點閱讀原文,領(lǐng)AI全套資料!

          瀏覽 32
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲色婷婷综合久久久中文 | www.俺来也.com | 成人AV一区二区三区在线观看 | 2019无码视频 | 亚洲中文字幕成人影视 |