Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
Web數據提取,通常被稱為Web Scraping或Web Crawling,是指從網頁中自動提取信息的過程。這項技術在市場研究、數據分析、信息聚合等多個領域都有廣泛的應用。Python社區提供了豐富的工具和庫來支持這一技術,其中BeautifulSoup和htmltab是兩個非常有用的庫。
BeautifulSoup是一個用于解析HTML和XML文檔的Python庫。它能夠將復雜的HTML文檔轉換成易于使用的Python對象,從而可以方便地提取網頁中的各種數據。BeautifulSoup的主要特點包括:
htmltab是一個專門用于從HTML中提取表格數據的Python庫。它提供了一種簡單的方式來識別和解析網頁中的表格,并將它們轉換為Python的列表或Pandas的DataFrame。htmltab的主要特點包括:
結合使用BeautifulSoup和htmltab可以大大提高Web數據提取的效率和靈活性。以下是一個簡單的示例,展示如何使用這兩個庫來提取Reddit子論壇中的表格數據。
首先,確保已經安裝了所需的庫。如果尚未安裝,可以通過pip安裝:
在上述示例中,我們首先設置了代理服務器,這對于繞過某些網站的IP封鎖非常有用。然后,我們定義了一個函數get_reddit_content,它接受一個Reddit子論壇的名稱作為參數,并返回該子論壇中的表格數據。 函數內部,我們使用requests.Session來發送GET請求,并設置了代理。然后,使用BeautifulSoup解析HTML內容,并利用htmltab庫來提取表格數據。最后,我們檢查響應狀態碼,如果請求成功,就打印出表格數據。
通過結合使用BeautifulSoup和htmltab,我們可以高效地從Web頁面中提取所需的數據。這種方法不僅適用于Reddit,還可以擴展到其他任何包含表格數據的網站。然而,需要注意的是,Web數據提取應當遵守目標網站的robots.txt文件規定,尊重版權和隱私政策。
者:George Seif
編譯:ronghuaiyang
雖然Pandas的功能非常強大,但是對于大數據集來說,確實是很慢的。
雖然 panda 是 Python 中用于數據處理的庫,但它并不是真正為了速度而構建的。了解一下新的庫 Modin,Modin 是為了分布式 panda 的計算來加速你的數據準備而開發的。
Pandas是處理 Python 數據的首選庫。它易于使用,并且在處理不同類型和大小的數據時非常靈活。它有大量的函數,使得操縱數據變得輕而易舉。
隨著時間的推移,各種Python包的流行程度
但是有一個缺點:對于較大的數據集來說,panda“慢”。
默認情況下,panda 使用單個 CPU 內核作為單個進程執行其函數。這對于較小的數據集工作得很好,因為你可能不會注意到速度上的差異。但是,隨著數據集越來越大,計算量越來越大,如果只使用單個 cpu 核,速度會受到很大的影響。它在數據集上同一時間只能計算一次,但該數據集可以有數百萬甚至數十億行。
然而,大多數用于數據科學的現代機器都有至少 2 個 CPU 核。這意味著,以 2 個 CPU 核為例,在使用 pandas 時,50%或更多的計算機處理能力在默認情況下不會執行任何操作。當你使用 4 核(現代 Intel i5)或 6 核(現代 Intel i7)時,情況會變得更糟。pandas 的設計初衷并不是為了有效利用這種計算能力。
Modin是一個新的庫,通過在系統所有可用的 CPU 核上自動分配計算來加速 pandas。有了它,對于任何尺寸的 pandas 數據數據集,Modin 聲稱能夠以 CPU 內核的數量得到近乎線性的加速。
讓我們看看它是如何工作的,并通過一些代碼示例進行說明。
給定 pandas 中的 DataFrame ,我們的目標是以盡可能快的方式對其執行某種計算或處理。可以用*.mean()取每一列的平均值,用groupby對數據進行分組,用drop_duplicates()*刪除所有重復項,或者使用其他任何內置的 pandas 函數。
在前一節中,我們提到了 pandas 如何只使用一個 CPU 核進行處理。自然,這是一個很大的瓶頸,特別是對于較大的 DataFrames,計算時就會表現出資源的缺乏。
理論上,并行計算就像在每個可用的 CPU 核上的不同數據點上應用計算一樣簡單。對于一個 pandas 的 DataFrame,一個基本的想法是將 DataFrame 分成幾個部分,每個部分的數量與你擁有的 CPU 內核的數量一樣多,并讓每個 CPU 核在一部分上運行計算。最后,我們可以聚合結果,這是一個計算上很 cheap 的操作。
多核系統如何更快地處理數據。對于單核進程(左),所有10個任務都放在一個節點上。對于雙核進程(右圖),每個節點承擔5個任務,從而使處理速度加倍。
這正是 Modin 所做的。它將 DataFrame 分割成不同的部分,這樣每個部分都可以發送到不同的 CPU 核。Modin 在行和列之間劃分 DataFrame。這使得 Modin 的并行處理可擴展到任何形狀的 DataFrame。
想象一下,如果給你一個列多行少的 DataFrame。有些庫只執行跨行分區,在這種情況下效率很低,因為我們的列比行多。但是對于 Modin 來說,由于分區是跨兩個維度進行的,所以并行處理對于所有形狀的數據流都是有效的,不管它們是更寬的(很多列)、更長的(很多行),還是兩者都有。
panda的DataFrame(左)存儲為一個塊,只發送到一個CPU核。Modin的DataFrame(右)跨行和列進行分區,每個分區可以發送到不同的CPU核上,直到用光系統中的所有CPU核。
上面的圖是一個簡單的例子。Modin 實際上使用了一個“分區管理器”,它可以根據操作的類型改變分區的大小和形狀。例如,可能有一個操作需要整個行或整個列。在這種情況下,“分區管理器”將以它能找到的最優方式執行分區和分配到 CPU 核上。它是非常靈活的。
為了在執行并行處理時完成大量繁重的工作,Modin 可以使用 Dask 或 Ray。它們都是使用 Python api 的并行計算庫,你可以選擇一個或另一個在運行時與 Modin 一起使用。Ray 目前是最安全的一個,因為它更穩定 —— Dask 后端是實驗性的。
已經有足夠的理論了。讓我們來看看代碼和速度基準測試!
安裝 Modin 的最簡單的方法是通過 pip。下面的命令安裝 Modin、Ray 和所有相關的依賴項:
pip install modin[ray]
對于我們下面的例子和 benchmarks,我們使用了 Kaggle 的 CS:GO Competitive Matchmaking Data。CSV 的每一行都包含了 CS:GO 比賽中的一輪數據。
現在,我們嘗試使用最大的 CSV 文件(有幾個),esea_master_dmg_demo .part1.csv,它有 1.2GB。有了這樣的體量,我們應該能夠看到 pandas 有多慢,以及 Modin 是如何幫助我們加速的。對于測試,我使用一個 i7-8700k CPU,它有 6 個物理內核和 12 個線程。
我們要做的第一個測試是使用 read_csv()讀取數據。Pandas 和 Modin 的代碼是完全一樣的。
### Read in the data with Pandas
import pandas as pd
s = time.time()
df = pd.read_csv("esea_master_dmg_demos.part1.csv")
e = time.time()
print("Pandas Loading Time = {}".format(e-s))
### Read in the data with Modin
import modin.pandas as pd
s = time.time()
df = pd.read_csv("esea_master_dmg_demos.part1.csv")
e = time.time()
print("Modin Loading Time = {}".format(e-s))
為了測量速度,我導入了time模塊,并在read_csv()之前和之后放置了一個time()。panda 將數據從 CSV 加載到內存需要 8.38 秒,而 Modin 需要 3.22 秒。這是 2.6 倍的加速。對于只修改 import 語句來說,這不算太寒酸!
讓我們在 DataFrame 上做一些更復雜的處理。連接多個 DataFrames 是 panda 中的一個常見操作 — 我們可能有幾個或多個包含數據的 CSV 文件,然后必須一次讀取一個并連接它們。我們可以使用 panda 和 Modin 中的*pd.concat()*函數輕松做到這一點。
我們希望 Modin 能夠很好地處理這種操作,因為它要處理大量的數據。代碼如下所示。
import pandas as pd
df = pd.read_csv("esea_master_dmg_demos.part1.csv")
s = time.time()
df = pd.concat([df for _ in range(5)])
e = time.time()
print("Pandas Concat Time = {}".format(e-s))
import modin.pandas as pd
df = pd.read_csv("esea_master_dmg_demos.part1.csv")
s = time.time()
df = pd.concat([df for _ in range(5)])
e = time.time()
print("Modin Concat Time = {}".format(e-s))
在上面的代碼中,我們將 DataFrame 與自身連接了 5 次。pandas 在 3.56 秒內完成了連接操作,而 Modin 在 0.041 秒內完成,速度提高了 86.83 倍!看起來,即使我們只有 6 個 CPU 核心,DataFrame 的分區也有助于提高速度。
用于 DataFrame 清洗的 panda 函數是*.fillna()*函數。此函數查找 DataFrame 中的所有 NaN 值,并將它們替換為你選擇的值。panda 必須遍歷每一行和每一列來查找 NaN 值并替換它們。這是一個應用 Modin 的絕佳機會,因為我們要多次重復一個非常簡單的操作。
import pandas as pd
df = pd.read_csv("esea_master_dmg_demos.part1.csv")
s = time.time()
df = df.fillna(value=0)
e = time.time()
print("Pandas Concat Time = {}".format(e-s))
import modin.pandas as pd
df = pd.read_csv("esea_master_dmg_demos.part1.csv")
s = time.time()
df = df.fillna(value=0)
e = time.time()
print("Modin Concat Time = {}".format(e-s))
這次,Pandas 運行*.fillna()*用了 1.8 秒,而 Modin 用了 0.21 秒,8.57 倍的加速!
Modin 總是這么快嗎?
并不是這樣。
在有些情況下,panda 實際上比 Modin 更快,即使在這個有 5,992,097(近 600 萬)行的大數據集上也是如此。下表顯示了我進行的一些實驗中 panda 與 Modin 的運行時間。
正如你所看到的,在某些操作中,Modin 要快得多,通常是讀取數據并查找值。其他操作,如執行統計計算,在 pandas 中要快得多。
Modin 仍然是一個相當新的庫,并在不斷地發展和擴大。因此,并不是所有的 pandas 功能都被完全加速了。如果你在 Modin 中嘗試使用一個還沒有被加速的函數,它將默認為 panda,因此不會有任何代碼錯誤或錯誤。
默認情況下,Modin 將使用計算機上所有可用的 CPU 內核。在某些情況下,你可能希望限制 Modin 可以使用的 CPU 內核的數量,特別是如果你希望在其他地方使用這種計算能力。我們可以通過 Ray 中的初始化設置來限制 Modin 可以訪問的 CPU 內核的數量,因為 Modin 在后端使用它。
import ray
ray.init(num_cpus=4)
import modin.pandas as pd
在處理大數據時,數據集的大小超過系統上的內存(RAM)的情況并不少見。Modin 有一個特殊的標志,我們可以設置為“true”,這將使其進入“out of core”模式。這意味著 Modin 將使用你的磁盤作為你的內存溢出存儲,允許你處理比你的 RAM 大得多的數據集。我們可以設置以下環境變量來啟用此功能:
export MODIN_OUT_OF_CORE=true
這就是使用 Modin 加速 panda 函數的指南。只需修改 import 語句就可以很容易地做到這一點。希望你發現 Modin 至少在一些情況下對加速 panda有用。
英文原文:https://www.kdnuggets.com/2019/11/speed-up-pandas-4x.html
讀:Pandas 是一個強大的分析結構化數據的工具集,它的使用基礎是 Numpy(提供高性能的矩陣運算),用于數據挖掘和數據分析,同時也提供數據清洗功能。
本文收集了 Python 數據分析庫 Pandas 及相關工具的日常使用方法,備查,持續更新中。
作者:李慶輝
來源:華章科技
縮寫說明:
推薦資源:
# https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/
# https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/
# https://docs.conda.io/en/latest/miniconda.html
# excel 處理相關包 xlrd / openpyxl / xlsxwriter
# 解析網頁包 requests / lxml / html5lib / BeautifulSoup4
# 計算包:scipy
pip install jupyter pandas matplotlib
# 國外網絡慢,可指定國內源快速下載安裝
pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple
Conda 多 Python 版本環境:
# 創建新環境,<環境名稱>, python 版本
conda create -n py39 python=3.9
# 刪除環境
conda remove -n py39 --all
# 進入、激活環境
conda activate py39
# 退出環境
conda deactivate
# 查看所有虛擬環境及當前環境
conda info -e
啟動 Jupyter Notebook:jupyter notebook
快捷鍵及功能:
import pandas as pd # 最新為 1.4.1 版本 (2022-02-12)
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
# 從 CSV 文件導入數據
pd.read_csv('file.csv', name=['列名','列名2'])
# 從限定分隔符的文本文件導入數據
pd.read_table(filename, header=0)
# Excel 導入,指定 sheet 和表頭
pd.read_excel('file.xlsx', sheet_name=' 表1', header=0)
# 從 SQL 表/庫導入數據
pd.read_sql(query, connection_object)
# 從 JSON 格式的字符串導入數據
pd.read_json(json_string)
# 解析 URL、字符串或者 HTML 文件,抽取其中的 tables 表格
pd.read_html(url)
# 從你的粘貼板獲取內容,并傳給 read_table()
pd.read_clipboard()
# 從字典對象導入數據,Key 是列名,Value是數據
pd.DataFrame(dict)
# 導入字符串
from io import StringIO
pd.read_csv(StringIO(web_data.text))
# 導出數據到CSV文件
df.to_csv('filename.csv')
# 導出數據到Excel文件
df.to_excel('filename.xlsx', index=True)
# 導出數據到 SQL 表
df.to_sql(table_name, connection_object)
# 以Json格式導出數據到文本文件
df.to_json(filename)
# 其他
df.to_html() # 顯示 HTML 代碼
df.to_markdown() # 顯示 markdown 代碼
df.to_string() # 顯示格式化字符
df.to_latex(index=False) # LaTeX tabular, longtable
df.to_dict('split') # 字典, 格式 list/series/records/index
df.to_clipboard(sep=',', index=False) # 存入系統剪貼板
# 將兩個表格輸出到一個excel文件里面,導出到多個 sheet
writer=pd.ExcelWriter('new.xlsx')
df_1.to_excel(writer,sheet_name='第一個', index=False)
df_2.to_excel(writer,sheet_name='第二個', index=False)
writer.save() # 必須運行writer.save(),不然不能輸出到本地
# 寫法2
with pd.ExcelWriter('new.xlsx') as writer:
df1.to_excel(writer, sheet_name='第一個')
df2.to_excel(writer, sheet_name='第二個')
# 用 xlsxwriter 導出支持合并單元格、顏色、圖表等定制功能
# https://xlsxwriter.readthedocs.io/working_with_pandas.html
# 創建20行5列的隨機數組成的 DataFrame 對象
pd.DataFrame(np.random.rand(20,5))
# 從可迭代對象 my_list 創建一個 Series 對象
pd.Series(my_list)
# 增加一個日期索引
df.index = pd.date_range('1900/1/30', periods=df.shape[0])
# 創建隨機數據集
df = pd.util.testing.makeDataFrame()
# 創建隨機日期索引數據集
df = pd.util.testing.makePeriodFrame()
df = pd.util.testing.makeTimeDataFrame()
# 創建隨機混合類型數據集
df = pd.util.testing.makeMixedDataFrame()
df.head(n) # 查看 DataFrame 對象的前n行
df.tail(n) # 查看 DataFrame 對象的最后n行
df.sample(n) # 查看 n 個樣本,隨機
df.shape # 查看行數和列數
df.info() # 查看索引、數據類型和內存信息
df.describe() # 查看數值型列的匯總統計
df.dtypes # 查看各字段類型
df.axes # 顯示數據行和列名
df.mean() # 返回所有列的均值
df.mean(1) # 返回所有行的均值,下同
df.corr() # 返回列與列之間的相關系數
df.count() # 返回每一列中的非空值的個數
df.max() # 返回每一列的最大值
df.min() # 返回每一列的最小值
df.median() # 返回每一列的中位數
df.std() # 返回每一列的標準差
df.var() # 方差
s.mode() # 眾數
s.prod() # 連乘
s.cumprod() # 累積連乘,累乘
df.cumsum(axis=0) # 累積連加,累加
s.nunique() # 去重數量,不同值的量
df.idxmax() # 每列最大的值的索引名
df.idxmin() # 最小
df.columns # 顯示所有列名
df.team.unique() # 顯示列中的不重復值
# 查看 Series 對象的唯一值和計數, 計數占比: normalize=True
s.value_counts(dropna=False)
# 查看 DataFrame 對象中每一列的唯一值和計數
df.apply(pd.Series.value_counts)
df.duplicated() # 重復行
df.drop_duplicates() # 刪除重復行
# set_option、reset_option、describe_option 設置顯示要求
pd.get_option()
# 設置行列最大顯示數量,None 為不限制
pd.options.display.max_rows = None
pd.options.display.max_columns = None
df.col.argmin() # 最大值[最小值 .argmax()] 所在位置的自動索引
df.col.idxmin() # 最大值[最小值 .idxmax()] 所在位置的定義索引
# 累計統計
ds.cumsum() # 前邊所有值之和
ds.cumprod() # 前邊所有值之積
ds.cummax() # 前邊所有值的最大值
ds.cummin() # 前邊所有值的最小值
# 窗口計算(滾動計算)
ds.rolling(x).sum() #依次計算相鄰x個元素的和
ds.rolling(x).mean() #依次計算相鄰x個元素的算術平均
ds.rolling(x).var() #依次計算相鄰x個元素的方差
ds.rolling(x).std() #依次計算相鄰x個元素的標準差
ds.rolling(x).min() #依次計算相鄰x個元素的最小值
ds.rolling(x).max() #依次計算相鄰x個元素的最大值
df.columns = ['a','b','c'] # 重命名列名
df.columns = df.columns.str.replace(' ', '_') # 列名空格換下劃線
df.loc[df.AAA >= 5, ['BBB', 'CCC']] = 555 # 替換數據
df['pf'] = df.site_id.map({2: '小程序', 7:'M 站'}) # 將枚舉換成名稱
pd.isnull() # 檢查DataFrame對象中的空值,并返回一個 Boolean 數組
pd.notnull() # 檢查DataFrame對象中的非空值,并返回一個 Boolean 數組
df.drop(['name'], axis=1) # 刪除列
df.drop([0, 10], axis=0) # 刪除行
del df['name'] # 刪除列
df.dropna() # 刪除所有包含空值的行
df.dropna(axis=1) # 刪除所有包含空值的列
df.dropna(axis=1,thresh=n) # 刪除所有小于 n 個非空值的行
df.fillna(x) # 用x替換DataFrame對象中所有的空值
df.fillna(value={'prov':'未知'}) # 指定列的空值替換為指定內容
s.astype(float) # 將Series中的數據類型更改為 float 類型
df.index.astype('datetime64[ns]') # 轉化為時間格式
s.replace(1, 'one') # 用 ‘one’ 代替所有等于 1 的值
s.replace([1, 3],['one','three']) # 用'one'代替 1,用 'three' 代替 3
df.rename(columns=lambda x: x + 1) # 批量更改列名
df.rename(columns={'old_name': 'new_name'}) # 選擇性更改列名
df.set_index('column_one') # 更改索引列
df.rename(index=lambda x: x + 1) # 批量重命名索引
# 重新命名表頭名稱
df.columns = ['UID', '當前待打款金額', '認證姓名']
df['是否設置提現賬號'] = df['狀態'] # 復制一列
df.loc[:, ::-1] # 列順序反轉
df.loc[::-1] # 行順序反轉, 下方為重新定義索引
df.loc[::-1].reset_index(drop=True)
# 保留小數位,四舍六入五成雙
df.round(2) # 全部
df.round({'A': 1, 'C': 2}) # 指定列
df['Name'] = df.Name # 取列名的兩個方法
df[df.index == 'Jude'] # 按索引查詢要用 .index
df[df[col] > 0.5] # 選擇col列的值大于0.5的行
# 多條件查詢
df[(df['team'] == 'A') &
( df['Q1'] > 80) &
df.utype.isin(['老客', '老訪客'])]
# 篩選為空的內容
df[df.order.isnull()]
# 類似 SQL where in
df[df.team.isin('A','B')]
df[(df.team=='B') & (df.Q1 == 17)]
df[~(df['team'] == 'A') | ( df['Q1'] > 80)] # 非,或
df[df.Name.str.contains('張')] # 包含字符
df.sort_values(col1) # 按照列col1排序數據,默認升序排列
df.col1.sort_values() # 同上, -> s
df.sort_values(col2, ascending=False) # 按照列 col1 降序排列數據
# 先按列col1升序排列,后按col2降序排列數據
df.sort_values([col1,col2], ascending=[True,False])
df2 = pd.get_dummies(df, prefix='t_') # 將枚舉的那些列帶枚舉轉到列上
s.set_index().plot()
# 多索引處理
dd.set_index(['utype', 'site_id', 'p_day'], inplace=True)
dd.sort_index(inplace=True) # 按索引排序
dd.loc['新訪客', 2, '2019-06-22'].plot.barh() # loc 中按順序指定索引內容
# 前100行, 不能指定行,如:df[100]
df[:100]
# 只取指定行
df1 = df.loc[0:, ['設計師ID', '姓名']]
# 將ages平分成5個區間并指定 labels
ages = np.array([1,5,10,40,36,12,58,62,77,89,100,18,20,25,30,32])
pd.cut(ages, [0,5,20,30,50,100],
labels=[u"嬰兒",u"青年",u"中年",u"壯年",u"老年"])
daily_index.difference(df_work_day.index) # 取出差別
# 格式化
df.index.name # 索引的名稱 str
df.columns.tolist()
df.values.tolist()
df.總人口.values.tolist()
data.apply(np.mean) # 對 DataFrame 中的每一列應用函數 np.mean
data.apply(np.max,axis=1) # 對 DataFrame 中的每一行應用函數 np.max
df.insert(1, 'three', 12, allow_duplicates=False) # 插入列 (位置、列名、[值])
df.pop('class') # 刪除列
# 增加一行
df.append(pd.DataFrame({'one':2,
'two':3,
'three': 4.4},
index=['f']),
sort=True)
# 指定新列
iris.assign(sepal_ratio=iris['SepalWidth'] / iris['SepalLength']).head()
df.assign(rate=lambda df: df.orders/df.uv)
# shift 函數是對數據進行平移動的操作
df['增幅'] = df['國內生產總值'] - df['國內生產總值'].shift(-1)
df.tshift(1) # 時間移動,按周期
# 和上相同,diff 函數是用來將數據進行移動之后與原數據差
# 異數據,等于 df.shift()-df
df['增幅'] = df['國內生產總值'].diff(-1)
# 留存數據,因為最大一般為數據池
df.apply(lambda x: x/x.max(), axis=1)
# 取 best 列中值為列名的值寫到 name 行上
df['value'] = df.lookup(df['name'], df['best'])
s.where(s > 1, 10) # 滿足條件下數據替換(10,空為 NaN)
s.mask(s > 0) # 留下滿足條件的,其他的默認為 NaN
# 所有值加 1 (加減乘除等)
df + 1 / df.add(1)
# 管道方法,鏈式調用函數,f(df)=df.pipe(f)
def gb(df, by):
result = df.copy()
result = result.groupby(by).sum()
return result
# 調用
df.pipe(gb, by='team')
# 窗口計算 '2s' 為兩秒
df.rolling(2).sum()
# 在窗口結果基礎上的窗口計算
df.expanding(2).sum()
# 超出(大于、小于)的值替換成對應值
df.clip(-4, 6)
# AB 兩列想加增加 C 列
df['C'] = df.eval('A+B')
# 和上相同效果
df.eval('C = A + B', inplace=True)
# 數列的變化百分比
s.pct_change(periods=2)
# 分位數, 可實現時間的中間點
df.quantile(.5)
# 排名 average, min,max,first,dense, 默認 average
s.rank()
# 數據爆炸,將本列的類列表數據和其他列的數據展開鋪開
df.explode('A')
# 枚舉更新
status = {0:'未執行', 1:'執行中', 2:'執行完畢', 3:'執行異常'}
df['taskStatus'] = df['taskStatus'].apply(status.get)
df.assign(金額=0) # 新增字段
df.loc[('bar', 'two'), 'A'] # 多索引查詢
df.query('i0 == "b" & i1 == "b"') # 多索引查詢方法 2
# 取多索引中指定級別的所有不重復值
df.index.get_level_values(2).unique()
# 去掉為零小數,12.00 -> 12
df.astype('str').applymap(lambda x: x.replace('.00', ''))
# 插入數據,在第三列加入「兩倍」列
df.insert(3, '兩倍', df['值']*2)
# 枚舉轉換
df['gender'] = df.gender.map({'male':'男', 'female':'女'})
# 增加本行之和列
df['Col_sum'] = df.apply(lambda x: x.sum(), axis=1)
# 對指定行進行加和
col_list= list(df)[2:] # 取請假范圍日期
df['總天數'] = df[col_list].sum(axis=1) # 計算總請假天數
# 對列求和,匯總
df.loc['col_sum'] = df.apply(lambda x: x.sum())
# 按指定的列表順序顯示
df.reindex(order_list)
# 按指定的多列排序
df.reindex(['col_1', 'col_5'], axis="columns")
df[col] # 根據列名,并以Series的形式返回列
df[[col1, col2]] # 以DataFrame形式返回多列
df.loc[df['team'] == 'B',['name']] # 按條件查詢,只顯示name 列
s.iloc[0] # 按位置選取數據
s.loc['index_one'] # 按索引選取數據
df.loc[0,'A':'B'] # A到 B 字段的第一行
df.loc[2018:1990, '第一產業增加值':'第三產業增加值']
df.loc[0,['A','B']] # d.loc[位置切片, 字段]
df.iloc[0,:] # 返回第一行, iloc 只能是數字
df.iloc[0,0] # 返回第一列的第一個元素
dc.query('site_id > 8 and utype=="老客"').head() # 可以 and or / & |
# 迭代器及使用
for idx,row in df.iterrows(): row['id']
# 迭代器對每個元素進行處理
df.loc[i,'鏈接'] = f'http://www.gairuo.com/p/{slug}.html'
for i in df.Name:print(i) # 迭代一個列
# 按列迭代,[列名, 列中的數據序列 S(索引名 值)]
for label, content in df.items():print(label, content)
# 按行迭代,迭代出整行包括索引的類似列表的內容,可row[2]取
for row in df.itertuples():print(row)
df.at[2018, '總人口'] # 按行列索引名取一個指定的單個元素
df.iat[1, 2] # 索引和列的編號取單個元素
s.nlargest(5).nsmallest(2) # 最大和最小的前幾個值
df.nlargest(3, ['population', 'GDP'])
df.take([0, 3]) # 指定多個行列位置的內容
# 按行列截取掉部分內容,支持日期索引標簽
ds.truncate(before=2, after=4)
# 將 dataframe 轉成 series
df.iloc[:,0]
float(str(val).rstrip('%')) # 百分數轉數字
df.reset_index(inplace=True) # 取消索引
df.groupby(col) # 返回一個按列col進行分組的Groupby對象
df.groupby([col1,col2]) # 返回一個按多列進行分組的Groupby對象
df.groupby(col1)[col2] # 返回按列col1進行分組后,列col2的均值
# 創建一個按列col1進行分組,并計算col2和col3的最大值的數據透視表
df.pivot_table(index=col1,
values=[col2,col3],
aggfunc=max,
as_index=False)
# 同上
df.pivot_table(index=['site_id', 'utype'],
values=['uv_all', 'regist_num'],
aggfunc=['max', 'mean'])
df.groupby(col1).agg(np.mean) # 返回按列col1分組的所有列的均值
# 按列將其他列轉行
pd.melt(df, id_vars=["day"], var_name='city', value_name='temperature')
# 交叉表是用于統計分組頻率的特殊透視表
pd.crosstab(df.Nationality,df.Handedness)
# groupby 后排序,分組 agg 內的元素取固定個數
(
df[(df.p_day >= '20190101')]
.groupby(['p_day', 'name'])
.agg({'uv':sum})
.sort_values(['p_day','uv'], ascending=[False, False])
.groupby(level=0).head(5) # 每天取5個頁面
.unstack()
.plot()
)
# 合并查詢經第一個看(max, min, last, size:數量)
df.groupby('結算類型').first()
# 合并明細并分組統計加總('max', `mean`, `median`,
# `prod`, `sum`, `std`,`var`, 'nunique'),'nunique'為去重的列表
df1 = df.groupby(by='設計師ID').agg({'結算金額':sum})
df.groupby(by=df.pf).ip.nunique() # groupby distinct, 分組+去重數
df.groupby(by=df.pf).ip.value_counts() # groupby 分組+去重的值及數量
df.groupby('name').agg(['sum', 'median', 'count'])
# 合并拼接行
# 將df2中的行添加到df1的尾部
df1.append(df2)
# 指定列合并成一個新表新列
ndf = (df['提名1']
.append(df['提名2'], ignore_index=True)
.append(df['提名3'], ignore_index=True))
ndf = pd.DataFrame(ndf, columns=(['姓名']))
# 將df2中的列添加到df1的尾部
df.concat([df1, df2], axis=1)
# 合并文件的各行
df1 = pd.read_csv('111.csv', sep='\t')
df2 = pd.read_csv('222.csv', sep='\t')
excel_list = [df1, df2]
# result = pd.concat(excel_list).fillna('')[:].astype('str')
result = pd.concat(excel_list)[]
result.to_excel('333.xlsx', index=False)
# 合并指定目錄下所有的 excel (csv) 文件
import glob
files = glob.glob("data/cs/*.xls")
dflist = []
for i in files:
dflist.append(pd.read_excel(i, usecols=['ID', '時間', '名稱']))
df = pd.concat(dflist)
# 合并增加列
# 對df1的列和df2的列執行SQL形式的join
df1.join(df2,on=col1,how='inner')
# 用 key 合并兩個表
df_all = pd.merge(df_sku, df_spu,
how='left',
left_on=df_sku['product_id'],
right_on=df_spu['p.product_id'])
# 時間索引
df.index = pd.DatetimeIndex(df.index)
# 時間只保留日期
df['date'] = df['time'].dt.date
# 將指定字段格式化為時間類型
df["date"] = pd.to_datetime(df['時間'])
# 轉化為北京時間
df['time'] = df['time'].dt.tz_convert('Asia/Shanghai')
# 轉為指定格式,可能會失去秒以后的精度
df['time'] = df['time'].dt.strftime("%Y-%m-%d %H:%M:%S")
dc.index = pd.to_datetime(dc.index, format='%Y%m%d', errors='ignore')
# 時間,參與運算
pd.DateOffset(days=2)
# 當前時間
pd.Timestamp.now()
pd.to_datetime('today')
# 判斷時間是否當天
pd.datetime.today().year == df.start_work.dt.year
df.time.astype('datetime64[ns]').dt.date == pd.to_datetime('today')
# 定義個天數
import datetime
days = lambda x: datetime.timedelta(days=x)
days(2)
# 同上,直接用 pd 包裝的
pd.Timedelta(days=2)
# unix 時間戳
pd.to_datetime(ted.film_date, unit='ms')
# 按月(YMDHminS)采集合計數據
df.set_index('date').resample('M')['quantity'].sum()
df.set_index('date').groupby('name')['ext price'].resample("M").sum()
# 按天匯總,index 是 datetime 時間類型
df.groupby(by=df.index.date).agg({'uu':'count'})
# 按周匯總
df.groupby(by=df.index.weekday).uu.count()
# 按月進行匯總
df.groupby(['name', pd.Grouper(key='date', freq='M')])['ext price'].sum()
# 按月進行匯總
df.groupby(pd.Grouper(key='day', freq='1M')).sum()
# 按照年度,且截止到12月最后一天統計 ext price 的 sum 值
df.groupby(['name', pd.Grouper(key='date', freq='A-DEC')])['ext price'].sum()
# 按月的平均重新采樣
df['Close'].resample('M').mean()
# https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#offset-aliases
# 取時間范圍,并取工作日
rng = pd.date_range(start="6/1/2016",end="6/30/2016",freq='B')
# 重新定時數據頻度,按一定補充方法
df.asfreq('D', method='pad')
# 時區,df.tz_convert('Europe/Berlin')
df.time.tz_localize(tz='Asia/Shanghai')
# 轉北京時間
df['Time'] = df['Time'].dt.tz_localize('UTC').dt.tz_convert('Asia/Shanghai')
# 查看所有時區
from pytz import all_timezones
print (all_timezones)
# 時長,多久,兩個時間間隔時間,時差
df['duration'] = pd.to_datetime(df['end']) - pd.to_datetime(df['begin'])
# 指定時間進行對比
df.Time.astype('datetime64[ns]') < pd.to_datetime('2019-12-11 20:00:00', format='%Y-%m-%d %H:%M:%S')
# 解決科學計數法問題
df = pd.read_csv('111.csv', sep='\t').fillna('')[:].astype('str')
# 和訂單量相關性最大到小顯示
dd.corr().total_order_num.sort_values(ascending=False)
# 解析列表、json 字符串
import ast
ast.literal_eval("[{'id': 7, 'name': 'Funny'}]")
# Series apply method applies a function to
# every element in a Series and returns a Series
ted.ratings.apply(str_to_list).head()
# lambda is a shorter alternative
ted.ratings.apply(lambda x: ast.literal_eval(x))
# an even shorter alternative is to apply the
# function directly (without lambda)
ted.ratings.apply(ast.literal_eval)
# 索引 index 使用 apply()
df.index.to_series().apply()
# https://pbpython.com/styling-pandas.html
df['per_cost'] = df['per_cost'].map('{:,.2f}%'.format) # 顯示%比形式
# 指定列表(值大于0)加背景色
df.style.applymap(lambda x: 'background-color: grey' if x>0 else '',
subset=pd.IndexSlice[:, ['B', 'C']])
# 最大值最小值加背景色
df.style.highlight_max(color='lightgreen').highlight_min(color='#cd4f39')
df.style.format('{:.2%}', subset=pd.IndexSlice[:, ['B']]) # 顯示百分號
# 指定各列的樣式
format_dict = {'sum':'${0:,.0f}',
'date': '{:%Y-%m}',
'pct_of_total': '{:.2%}'
'c': str.upper}
# 一次性樣式設置
(df.style.format(format_dict) # 多種樣式形式
.hide_index()
# 指定列按顏色深度表示值大小, cmap 為 matplotlib colormap
.background_gradient(subset=['sum_num'], cmap='BuGn')
# 表格內作橫向 bar 代表值大小
.bar(color='#FFA07A', vmin=100_000, subset=['sum'], align='zero')
# 表格內作橫向 bar 代表值大小
.bar(color='lightgreen', vmin=0, subset=['pct_of_total'], align='zero')
# 下降(小于0)為紅色, 上升為綠色
.bar(color=['#ffe4e4','#bbf9ce'], vmin=0, vmax=1, subset=['增長率'], align='zero')
# 給樣式表格起個名字
.set_caption('2018 Sales Performance')
.hide_index())
# 按條件給整行加背景色(樣式)
def background_color(row):
if row.pv_num >= 10000:
return ['background-color: red'] * len(row)
elif row.pv_num >= 100:
return ['background-color: yellow'] * len(row)
return [''] * len(row)
# 使用
df.style.apply(background_color, axis=1)
import sparklines
import numpy as np
def sparkline_str(x):
bins=np.histogram(x)[0]
sl = ''.join(sparklines.sparklines(bins))
return sl
sparkline_str.__name__ = "sparkline"
# 畫出趨勢圖,保留兩位小數
df.groupby('name')['quantity', 'ext price'].agg(['mean', sparkline_str]).round(2)
# sparkline 圖形
# https://hugoworld.wordpress.com/2019/01/26/sparklines-in-jupyter-notebooks-ipython-and-pandas/
def sparkline(data, figsize=(4, 0.25), **kwargs):
"""
creates a sparkline
"""
# Turn off the max column width so the images won't be truncated
pd.set_option('display.max_colwidth', -1)
# Turning off the max column will display all the data
# if gathering into sets / array we might want to restrict to a few items
pd.set_option('display.max_seq_items', 3)
#Monkey patch the dataframe so the sparklines are displayed
pd.DataFrame._repr_html_ = lambda self: self.to_html(escape=False)
from matplotlib import pyplot as plt
import base64
from io import BytesIO
data = list(data)
*_, ax = plt.subplots(1, 1, figsize=figsize, **kwargs)
ax.plot(data)
ax.fill_between(range(len(data)), data, len(data)*[min(data)], alpha=0.1)
ax.set_axis_off()
img = BytesIO()
plt.savefig(img)
plt.close()
return '<img src="data:image/png;base64, {}" />'.format(base64.b64encode(img.getvalue()).decode())
# 使用
df.groupby('name')['quantity', 'ext price'].agg(['mean', sparkline])
df.apply(sparkline, axis=1) # 僅支持橫向數據畫線,可做 T 轉置
kind : str
常用方法:
df88.plot.bar(y='rate', figsize=(20, 10)) # 圖形大小,單位英寸
df_1[df_1.p_day > '2019-06-01'].plot.bar(x='p_day', y=['total_order_num','order_user'], figsize=(16, 6)) # 柱狀圖
# 每條線一個站點,各站點的 home_remain, stack的意思是堆疊,堆積
# unstack 即“不要堆疊”
(df[(df.p_day >= '2019-05-1') & (df.utype == '老客')].groupby(['p_day', 'site_id'])['home_remain'].sum().unstack().plot.line())
# 折線圖,多條, x 軸默認為 index
dd.plot.line(x='p_day', y=['uv_all', 'home_remain'])
dd.loc['新訪客', 2].plot.scatter(x='order_user', y='paid_order_user') # 散點圖
dd.plot.bar(color='blue') # 柱狀圖, barh 為橫向柱狀圖
sns.heatmap(dd.corr()) # 相關性可視化
# 刻度從0開始,指定范圍 ylim=(0,100), x 軸相同
s.plot.line(ylim=0)
# 折線顏色 https://matplotlib.org/examples/color/named_colors.html
# 樣式( '-','--','-.',':' )
# 折線標記 https://matplotlib.org/api/markers_api.html
# grid=True 顯示刻度 etc: https://matplotlib.org/api/_as_gen/matplotlib.pyplot.plot.html
s.plot.line(color='green', linestyle='-', marker='o')
# 兩個圖繪在一起
[df['數量'].plot.kde(), df['數量'].plot.hist()]
# 對表中的數據按顏色可視化
import seaborn as sns
cm = sns.light_palette("green", as_cmap=True)
df.style.background_gradient(cmap=cm, axis=1)
# 將數據轉化為二維數組
[i for i in zip([i.strftime('%Y-%m-%d') for i in s.index.to_list()], s.to_list())]
# 和 plot 用法一樣 https://hvplot.pyviz.org/user_guide/Plotting.html
import hvplot.pandas
# 打印 Sqlite 建表語句
print(pd.io.sql.get_schema(fdf, 'table_name'))
# jupyter notebooks plt 圖表配置
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = (15.0, 8.0) # 固定顯示大小
plt.rcParams['font.family'] = ['sans-serif'] # 顯示中文問題
plt.rcParams['font.sans-serif'] = ['SimHei'] # 顯示中文問題
# 輸出單行全部變量
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = 'all'
# jupyter notebooks 頁面自適應寬度
from IPython.core.display import display, HTML
display(HTML("<style>.container { width:100% !important; }</style>"))
# 背景白色 <style>#notebook_panel {background: #ffffff;}</style>
# jupyter notebooks 嵌入頁面內容
from IPython.display import IFrame
IFrame('https://arxiv.org/pdf/1406.2661.pdf', width=800, height=450)
# Markdown 一個 cell 不支持多張粘貼圖片
# 一個文件打印打開只顯示一張圖片問題解決
# /site-packages/notebook/static/notebook/js/main.min.js var key 處
# 33502、33504 行
key = utils.uuid().slice(2,6)+encodeURIandParens(blob.name);
key = utils.uuid().slice(2,6)+Object.keys(that.attachments).length;
# https://github.com/ihnorton/notebook/commit/55687c2dc08817da587977cb6f19f8cc0103bab1
# 多行輸出
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = 'all' #默認為'last'
# 執行 shell 命令: ! <命令語句>
# 在線可視化工具
https://plot.ly/create
安裝 RISE 庫:pip install RISE
關于作者:李慶輝,數據產品專家,某電商公司數據產品團隊負責人,擅長通過數據治理、數據分析、數據化運營提升公司的數據應用水平。
精通Python數據科學及Python Web開發,曾獨立開發公司的自動化數據分析平臺,參與教育部“1+X”數據分析(Python)職業技能等級標準評審。
中國人工智能學會會員,企業數字化、數據產品和數據分析講師,在個人網站“蓋若”上編寫的技術和產品教程廣受歡迎。
延伸閱讀
《深入淺出Pandas》
推薦語:這是一本全面覆蓋了Pandas使用者的普遍需求和痛點的著作,基于實用、易學的原則,從功能、使用、原理等多個維度對Pandas做了全方位的詳細講解,既是初學者系統學習Pandas難得的入門書,又是有經驗的Python工程師案頭必不可少的查詢手冊。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。