Pandas缺失值填充5大技巧

2023-08-25 08:27:29 浏览数 (2)

Pandas缺失值填充5大技巧

本文记录Pandas中缺失值填充的5大技巧:

  • 填充具体数值,通常是0
  • 填充某个统计值,比如均值、中位数、众数等
  • 填充前后项的值
  • 基于SimpleImputer类的填充
  • 基于KNN算法的填充

数据

代码语言:javascript复制
import pandas as pd
import numpy as np
代码语言:javascript复制
df = pd.DataFrame({
    "A":list(range(1,9)),
    "B":list(range(5,13)),
    "C":list(range(9,17)),

})

df

.dataframe tbody tr th:only-of-type { vertical-align: middle; } <pre><code>.dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </code></pre>

A

B

C

0

1

5

9

1

2

6

10

2

3

7

11

3

4

8

12

4

5

9

13

5

6

10

14

6

7

11

15

7

8

12

16

设置空值

代码语言:javascript复制
df.iloc[0,2] = np.nan
df.iloc[2,0] = np.nan
df.iloc[3,1] = np.nan
df.iloc[6,1] = np.nan
df.iloc[7,2] = np.nan

df

.dataframe tbody tr th:only-of-type { vertical-align: middle; } <pre><code>.dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </code></pre>

A

B

C

0

1.0

5.0

NaN

1

2.0

6.0

10.0

2

NaN

7.0

11.0

3

4.0

NaN

12.0

4

5.0

9.0

13.0

5

6.0

10.0

14.0

6

7.0

NaN

15.0

7

8.0

12.0

NaN

统计空值个数

代码语言:javascript复制
# 统计每列下空值的个数
df.isnull().sum()
代码语言:javascript复制
A    1
B    2
C    2
dtype: int64
代码语言:javascript复制
df[(df.isnull()).any(axis=1)]

.dataframe tbody tr th:only-of-type { vertical-align: middle; } <pre><code>.dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </code></pre>

A

B

C

0

1.0

5.0

NaN

2

NaN

7.0

11.0

3

4.0

NaN

12.0

6

7.0

NaN

15.0

7

8.0

12.0

NaN

方法1:填充具体数值

代码语言:javascript复制
df.fillna(0)  # 一般是填充0

.dataframe tbody tr th:only-of-type { vertical-align: middle; } <pre><code>.dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </code></pre>

A

B

C

0

1.0

5.0

0.0

1

2.0

6.0

10.0

2

0.0

7.0

11.0

3

4.0

0.0

12.0

4

5.0

9.0

13.0

5

6.0

10.0

14.0

6

7.0

0.0

15.0

7

8.0

12.0

0.0

代码语言:javascript复制
df.fillna(33)  # 填充其他数值

.dataframe tbody tr th:only-of-type { vertical-align: middle; } <pre><code>.dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </code></pre>

A

B

C

0

1.0

5.0

33.0

1

2.0

6.0

10.0

2

33.0

7.0

11.0

3

4.0

33.0

12.0

4

5.0

9.0

13.0

5

6.0

10.0

14.0

6

7.0

33.0

15.0

7

8.0

12.0

33.0

方法2:填充统计值

代码语言:javascript复制
df1 = df.copy()  # 方便演示,生成副本
代码语言:javascript复制
df1["A"].mean()
代码语言:javascript复制
4.714285714285714
代码语言:javascript复制
(1 2 4 5 6 7 8) / 7
代码语言:javascript复制
4.714285714285714
代码语言:javascript复制
# 每列的空值填充各自的均值

for column in df1.columns.tolist():
    m = df1[column].mean()  # 列均值:mean可以改成max、min、mode等
    df1[column] = df1[column].fillna(m)  # 填充每个列
df1

.dataframe tbody tr th:only-of-type { vertical-align: middle; } <pre><code>.dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </code></pre>

A

B

C

0

1.000000

5.000000

12.5

1

2.000000

6.000000

10.0

2

4.714286

7.000000

11.0

3

4.000000

8.166667

12.0

4

5.000000

9.000000

13.0

5

6.000000

10.000000

14.0

6

7.000000

8.166667

15.0

7

8.000000

12.000000

12.5

方法3:前后项填充

代码语言:javascript复制
df2 = df.copy()  # 生成副本
df2  # 替换前

.dataframe tbody tr th:only-of-type { vertical-align: middle; } <pre><code>.dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </code></pre>

A

B

C

0

1.0

5.0

NaN

1

2.0

6.0

10.0

2

NaN

7.0

11.0

3

4.0

NaN

12.0

4

5.0

9.0

13.0

5

6.0

10.0

14.0

6

7.0

NaN

15.0

7

8.0

12.0

NaN

代码语言:javascript复制
# 1、前项填充 f-forward
df2.fillna(method="ffill",axis=0, inplace=True)  # 原地替换

df2

.dataframe tbody tr th:only-of-type { vertical-align: middle; } <pre><code>.dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </code></pre>

A

B

C

0

1.0

5.0

NaN

1

2.0

6.0

10.0

2

2.0

7.0

11.0

3

4.0

7.0

12.0

4

5.0

9.0

13.0

5

6.0

10.0

14.0

6

7.0

10.0

15.0

7

8.0

12.0

15.0

代码语言:javascript复制
# 2、后项填充 b-back
df2.fillna(method="bfill",axis=0, inplace=True)

df2  # 替换后

.dataframe tbody tr th:only-of-type { vertical-align: middle; } <pre><code>.dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </code></pre>

A

B

C

0

1.0

5.0

10.0

1

2.0

6.0

10.0

2

2.0

7.0

11.0

3

4.0

7.0

12.0

4

5.0

9.0

13.0

5

6.0

10.0

14.0

6

7.0

10.0

15.0

7

8.0

12.0

15.0

方法4:SimpleImputer类填充(单变量)

代码语言:javascript复制
sklearn.impute.SimpleImputer (missing_values=nan,
                              strategy=’mean’,
                              fill_value=None,
                              verbose=0,
                              copy=True)
  • missing_values:int, float, str, (默认)np.nan或是None, 指明缺失值长什么样子
  • strategy:空值填充的方法
    • mean:均值,默认
    • median:中位数
    • most_frequent:众数
    • constant:自定义的值,必须通过fill_value来定义。
  • fill_value:str或数值,默认为Zone。当strategy == “constant"时,fill_value被用来替换所有出现的缺失值(missing_values)。fill_value为Zone,当处理的是数值数据时,缺失值(missing_values)会替换为0,对于字符串或对象数据类型则替换为"missing_value” 这一字符串。
  • verbose:int,(默认)0,控制imputer的冗长。
  • copy:boolean,(默认)True,表示对数据的副本进行处理(原数据不改变),False对数据直接原地修改。
  • add_indicator:boolean,(默认)False,True则会在数据后面加入n列由0和1构成的同样大小的数据,0表示所在位置非缺失值,1表示所在位置为缺失值。
代码语言:javascript复制
from sklearn.impute import SimpleImputer
代码语言:javascript复制
# 案例1
df3 = df.copy() # 副本

# 使用impute.SimpleImputer类进行缺失值填充前,将其实例化
df3_mean = SimpleImputer(missing_values=np.nan, strategy='mean')   # 均值
df3_mean.fit_transform(df3)  # 结果是numpy数组
代码语言:javascript复制
array([[ 1.        ,  5.        , 12.5       ],
       [ 2.        ,  6.        , 10.        ],
       [ 4.71428571,  7.        , 11.        ],
       [ 4.        ,  8.16666667, 12.        ],
       [ 5.        ,  9.        , 13.        ],
       [ 6.        , 10.        , 14.        ],
       [ 7.        ,  8.16666667, 15.        ],
       [ 8.        , 12.        , 12.5       ]])
代码语言:javascript复制
df3  # 不是原地修改,df3不会改变

.dataframe tbody tr th:only-of-type { vertical-align: middle; } <pre><code>.dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </code></pre>

A

B

C

0

1.0

5.0

NaN

1

2.0

6.0

10.0

2

NaN

7.0

11.0

3

4.0

NaN

12.0

4

5.0

9.0

13.0

5

6.0

10.0

14.0

6

7.0

NaN

15.0

7

8.0

12.0

NaN

代码语言:javascript复制
# 案例2

df3_mean = SimpleImputer(
    missing_values=np.nan,
    strategy='median',  # 中位数
    copy=False  # 直接原地修改
    )

df3_mean.fit_transform(df3)
代码语言:javascript复制
array([[ 1. ,  5. , 12.5],
       [ 2. ,  6. , 10. ],
       [ 5. ,  7. , 11. ],
       [ 4. ,  8. , 12. ],
       [ 5. ,  9. , 13. ],
       [ 6. , 10. , 14. ],
       [ 7. ,  8. , 15. ],
       [ 8. , 12. , 12.5]])
代码语言:javascript复制
df3  # df3已经改变

.dataframe tbody tr th:only-of-type { vertical-align: middle; } <pre><code>.dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </code></pre>

A

B

C

0

1.0

5.0

12.5

1

2.0

6.0

10.0

2

5.0

7.0

11.0

3

4.0

8.0

12.0

4

5.0

9.0

13.0

5

6.0

10.0

14.0

6

7.0

8.0

15.0

7

8.0

12.0

12.5

代码语言:javascript复制
# 案例3:不同的列采取不同策略填充

df4 = df.copy()

#均值
df_mean = SimpleImputer(missing_values=np.nan, strategy='mean',copy=False)
#中位数
df_median = SimpleImputer(missing_values=np.nan, strategy='median',copy=False)
#常数0
df_0 = SimpleImputer(strategy="constant",fill_value=0,copy=False)
#众数
df_most_frequent = SimpleImputer(missing_values=np.nan, strategy='most_frequent',copy=False)
代码语言:javascript复制
df4["A"] = df_mean.fit_transform(df4["A"].values.reshape(-1,1))   # 均值
df4["B"] = df_median.fit_transform(df4["B"].values.reshape(-1,1))  # 中位数
df4["C"] = df_most_frequent.fit_transform(df4["C"].values.reshape(-1,1))  # 众数

df4 # 原地修改

.dataframe tbody tr th:only-of-type { vertical-align: middle; } <pre><code>.dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </code></pre>

A

B

C

0

1.000000

5.0

10.0

1

2.000000

6.0

10.0

2

4.714286

7.0

11.0

3

4.000000

8.0

12.0

4

5.000000

9.0

13.0

5

6.000000

10.0

14.0

6

7.000000

8.0

15.0

7

8.000000

12.0

10.0

方法5:基于KNN填充

代码语言:javascript复制
from sklearn.impute import KNNImputer
代码语言:javascript复制
df5 = df.copy()
df5  # 填充前

.dataframe tbody tr th:only-of-type { vertical-align: middle; } <pre><code>.dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </code></pre>

A

B

C

0

1.0

5.0

NaN

1

2.0

6.0

10.0

2

NaN

7.0

11.0

3

4.0

NaN

12.0

4

5.0

9.0

13.0

5

6.0

10.0

14.0

6

7.0

NaN

15.0

7

8.0

12.0

NaN

代码语言:javascript复制
# 最近的3个邻居,使用的是3者的均值

impute = KNNImputer(n_neighbors=3)
impute.fit_transform(df5)
代码语言:javascript复制
array([[ 1.        ,  5.        , 11.        ],
       [ 2.        ,  6.        , 10.        ],
       [ 2.33333333,  7.        , 11.        ],
       [ 4.        ,  7.33333333, 12.        ],
       [ 5.        ,  9.        , 13.        ],
       [ 6.        , 10.        , 14.        ],
       [ 7.        , 10.33333333, 15.        ],
       [ 8.        , 12.        , 14.        ]])

填充值如何计算得来:

代码语言:javascript复制
print((1   2   4) / 3)

print((6   7   9) / 3)
print((9   10   12) / 3)

print((10   11   12) / 3)
print((13   14   15) / 3)
代码语言:javascript复制
2.3333333333333335
7.333333333333333
10.333333333333334
11.0
14.0

0 人点赞