pandas逐行操作、分箱技術、窗口函數


cummax,cummin,cumprod,cumsum

有時候我們需要求出從第一行開始截止到當前行的最大值、最小值,以及實現累乘、累和等等。

import pandas as pd


df = pd.DataFrame({"a": [10, 20, 15, 50, 40]})

# cummax:求出從第一行開始截止到當前行的最大值
# 第1行為10,第2行為20,第3行為15但是比20小所以還是20,第4行為50,同理第5行也是50
print(df["a"].cummax())
"""
0    10
1    20
2    20
3    50
4    50
Name: a, dtype: int64
"""

# 這個不需要解釋了
print(df["a"].cummin())
"""
0    10
1    10
2    10
3    10
4    10
Name: a, dtype: int64
"""

# 對每一行實現累乘
print(df["a"].cumprod())
"""
0         10
1        200
2       3000
3     150000
4    6000000
Name: a, dtype: int64
"""

# 對每一行實現累加
print(df["a"].cumsum())
"""
0     10
1     30
2     45
3     95
4    135
Name: a, dtype: int64
"""

shift:垂直方向移動

import pandas as pd


df = pd.DataFrame({"a": range(1, 10)})
print(df)
"""
   a
0  1
1  2
2  3
3  4
4  5
5  6
6  7
7  8
8  9
"""

df["b"] = df["a"].shift(1)
df["c"] = df["a"].shift(-1)
print(df)
"""
   a    b    c
0  1  NaN  2.0
1  2  1.0  3.0
2  3  2.0  4.0
3  4  3.0  5.0
4  5  4.0  6.0
5  6  5.0  7.0
6  7  6.0  8.0
7  8  7.0  9.0
8  9  8.0  NaN
"""

我們看到,我們某一列使用shift(n),可以使其達到向上或者向下的平移效果。n大於0,表示向上平移n個單位,n小於0表示向下平移n個單位。既然平移了,那么勢必就會出現NaN。

想象一個框,shift(1)表示框向上平移一個長度,那么框住的部分就是新的列。

如果我們有這樣一個需求,計算某一列的當前元素和上一個元素的差,該怎么做呢?

import pandas as pd


df = pd.DataFrame({"a": [10, 20, 15, 50, 40]})

print(df["a"] - df["a"].shift(1))
"""
0     NaN
1    10.0
2    -5.0
3    35.0
4   -10.0
Name: a, dtype: float64
"""

diff:垂直方向相減

這個功能我們已經實現了,可以使用shift平移之后手動相減。但是有一個更簡便的方法,也就是diff(n),n大於0,表示當前行與前第n行相減,n小於0,表示當前行與后第n行相減。

import pandas as pd


df = pd.DataFrame({"a": [10, 20, 15, 50, 40]})

df["b"] = df["a"].diff(1)
df["c"] = df["a"].diff(-1)
print(df)
"""
    a     b     c
0  10   NaN -10.0
1  20  10.0   5.0
2  15  -5.0 -35.0
3  50  35.0  10.0
4  40 -10.0   NaN
"""

pct_change:垂直方向相減求比例

和diff(n)比較類似,但是在diff(n)基礎之上又做了一層操作。就是減完了之后,用差再除以原來減去的值。

import pandas as pd


df = pd.DataFrame({"a": [10, 20, 15, 50, 40]})

df["b"] = df["a"].diff(1)
df["b_pct"] = df["a"].pct_change(1)
df["c"] = df["a"].diff(-1)
df["c_pct"] = df["a"].pct_change(-1)
print(df)
"""
    a     b     b_pct     c     c_pct
0  10   NaN       NaN -10.0 -0.500000
1  20  10.0  1.000000   5.0  0.333333
2  15  -5.0 -0.250000 -35.0 -0.700000
3  50  35.0  2.333333  10.0  0.250000
4  40 -10.0 -0.200000   NaN       NaN
"""

cut:分箱技術

有時候,我們需要對數據進行分類。比如考生成績,凡是小於60的歸類為不及格,大於等於60小於80的為不錯,大於等於80小於等於100為優秀

import pandas as pd


df = pd.DataFrame({"a": [60, 50, 80, 96, 75]})

# bins:為一個數組,從小到大。
df["b"] = pd.cut(df["a"], bins=[0, 59, 79, 100])
# 還可以指定labels,注意:len(labels) == len(bins) - 1,因為bins如果有n個元素,那么會形成n-1個區間
df["c"] = pd.cut(df["a"], bins=[0, 59, 79, 100], labels=["不及格", "不錯", "優秀"])
print(df)
"""
    a          b    c
0  60   (59, 79]   不錯
1  50    (0, 59]  不及格
2  80  (79, 100]   優秀
3  96  (79, 100]   優秀
4  75   (59, 79]   不錯
"""

我們注意到:區間是左開右閉的,如果需要把右邊也改成開區間,那么加上right=False即可,默認是為True 

rolling:窗口函數

假設我們有一年的歷史數據,我們需要對每8天求一次平均值該怎么做呢?比如:第一行是1~8天的平均值,第二行是2~9天的平均值,第三行是3~10天的平均值。

import pandas as pd


df = pd.DataFrame({"a": [10, 20, 10, 60, 40, 20, 50]})

# 調用rolling(n)方法等於每n行開了一個窗口,然后對相應的窗口里面的數據進行操作。
# 然后就可以使用window求平均值了
# 這個n必須要大於0,否則報錯
window = df["a"].rolling(2)
# 我們說n大於0是往上,為2的話表示每一行往上數,加上本身數兩行,然后對這兩行求平均。所以第一行就是NaN了,因為上面沒有了。
print(window.mean())
"""
0     NaN
1    15.0
2    15.0
3    35.0
4    50.0
5    30.0
6    35.0
Name: a, dtype: float64
"""
# 同理n=3,表示往上數3行
# 那么第1行和第2行都會為NaN
print(df["a"].rolling(3).mean())
"""
0          NaN
1          NaN
2    13.333333
3    30.000000
4    36.666667
5    40.000000
6    36.666667
Name: a, dtype: float64
"""

# 當然不光可以求平均值,還可以求最大值,最小值,求和等等
df["b"] = df["a"].rolling(2).max()
df["c"] = df["a"].rolling(2).min()
df["d"] = df["a"].rolling(2).sum()
print(df)
"""
    a     b     c      d
0  10   NaN   NaN    NaN
1  20  20.0  10.0   30.0
2  10  20.0  10.0   30.0
3  60  60.0  10.0   70.0
4  40  60.0  40.0  100.0
5  20  40.0  20.0   60.0
6  50  50.0  20.0   70.0
"""

# 甚至還可以自定義函數
df["e"] = df["a"].rolling(2).sum()
# 每一個窗口可以理解為一個Series,df["a"].rolling(2).sum()等價於df["a"].rolling(2).agg("sum")
# 我們再單獨加上一個1
df["f"] = df["a"].rolling(2).agg(lambda x: sum(x) + 1)
print(df[["e", "f"]])
"""
       e      f
0    NaN    NaN
1   30.0   31.0
2   30.0   31.0
3   70.0   71.0
4  100.0  101.0
5   60.0   61.0
6   70.0   71.0
"""

# 如果n=1,那么就是本身了
# 不管調用什么方法,都是它本身, 因為只有窗口大小為1
print((df["a"].rolling(1).sum() == df["a"].rolling(1).min()).all())  # True


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM