Working with missing data

在本节中,我们将讨论pandas中的缺失(也称为NA)值。

注意

在内部使用NaN表示丢失数据的选择在很大程度上是出于简单性和性能原因。它与MaskedArray方法不同,例如scikits.timeseries我们希望NumPy很快能够提供一个原生NA类型的解决方案(类似于R)的性能足以用于熊猫。

有关某些高级策略,请参阅cookbook

Missing data basics

When / why does data become missing?

有些人可能会对我们使用缺少的产生疑惑。“缺少”我们只是指null或“不存在为什么原因”。许多数据集只是带有缺失数据到达,或者是因为它存在并且没有被收集或者它从来不存在。例如,在财务时间系列的集合中,某些时间系列可能在不同的日期开始。因此,在开始日期之前的值通常将被标记为缺失。

在pandas中,丢失数据引入到数据集中的最常见方法之一是通过重新索引。例如

In [1]: df = pd.DataFrame(np.random.randn(5, 3), index=['a', 'c', 'e', 'f', 'h'],
   ...:                   columns=['one', 'two', 'three'])
   ...: 

In [2]: df['four'] = 'bar'

In [3]: df['five'] = df['one'] > 0

In [4]: df
Out[4]: 
        one       two     three four   five
a  0.469112 -0.282863 -1.509059  bar   True
c -1.135632  1.212112 -0.173215  bar  False
e  0.119209 -1.044236 -0.861849  bar   True
f -2.104569 -0.494929  1.071804  bar  False
h  0.721555 -0.706771 -1.039575  bar   True

In [5]: df2 = df.reindex(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])

In [6]: df2
Out[6]: 
        one       two     three four   five
a  0.469112 -0.282863 -1.509059  bar   True
b       NaN       NaN       NaN  NaN    NaN
c -1.135632  1.212112 -0.173215  bar  False
d       NaN       NaN       NaN  NaN    NaN
e  0.119209 -1.044236 -0.861849  bar   True
f -2.104569 -0.494929  1.071804  bar  False
g       NaN       NaN       NaN  NaN    NaN
h  0.721555 -0.706771 -1.039575  bar   True

Values considered “missing”

由于数据有多种形式和形式,pandas旨在灵活处理丢失的数据。由于计算速度和方便性的原因,NaN是默认的缺失值标记,我们需要能够使用不同类型的数据轻松检测此值:浮点,整数,布尔值和常规对象。然而,在许多情况下,Python None将出现,我们希望也考虑“missing”或“null”。

注意

在版本v0.10.0 inf-inf之前,在计算中也被认为是“null”。默认情况下不再是这种情况;请使用mode.use_inf_as_null选项恢复它。

pandas为了更好的处理缺失值(包括不同列的不同类型), 提供了 isnull()notnull() 函数, 这两种方法都可以用在 SeriesDataFrame 对象上:

In [7]: df2['one']
Out[7]: 
a    0.469112
b         NaN
c   -1.135632
d         NaN
e    0.119209
f   -2.104569
g         NaN
h    0.721555
Name: one, dtype: float64

In [8]: pd.isnull(df2['one'])
Out[8]: 
a    False
b     True
c    False
d     True
e    False
f    False
g     True
h    False
Name: one, dtype: bool

In [9]: df2['four'].notnull()
Out[9]: 
a     True
b    False
c     True
d    False
e     True
f     True
g    False
h     True
Name: four, dtype: bool

In [10]: df2.isnull()
Out[10]: 
     one    two  three   four   five
a  False  False  False  False  False
b   True   True   True   True   True
c  False  False  False  False  False
d   True   True   True   True   True
e  False  False  False  False  False
f  False  False  False  False  False
g   True   True   True   True   True
h  False  False  False  False  False

警告

必须注意,在python(和numpy)中,nan's不比较相等,但None's doNote that Pandas/numpy uses the fact that np.nan != np.nan, and treats None like np.nan.

In [11]: None == None
Out[11]: True

In [12]: np.nan == np.nan
Out[12]: False

因此,与上述相比,标量等式比较与None/np.nan不提供有用的信息。

In [13]: df2['one'] == np.nan
Out[13]: 
a    False
b    False
c    False
d    False
e    False
f    False
g    False
h    False
Name: one, dtype: bool

Datetimes

对于datetime64 [ns]类型,NaT表示缺少的值。这是一个伪本地的哨兵值,可以用单数dtype(datetime64 [ns])中的numpy表示。pandas对象提供NaTNaN之间的相互兼容性。

In [14]: df2 = df.copy()

In [15]: df2['timestamp'] = pd.Timestamp('20120101')

In [16]: df2
Out[16]: 
        one       two     three four   five  timestamp
a  0.469112 -0.282863 -1.509059  bar   True 2012-01-01
c -1.135632  1.212112 -0.173215  bar  False 2012-01-01
e  0.119209 -1.044236 -0.861849  bar   True 2012-01-01
f -2.104569 -0.494929  1.071804  bar  False 2012-01-01
h  0.721555 -0.706771 -1.039575  bar   True 2012-01-01

In [17]: df2.ix[['a','c','h'],['one','timestamp']] = np.nan

In [18]: df2
Out[18]: 
        one       two     three four   five  timestamp
a       NaN -0.282863 -1.509059  bar   True        NaT
c       NaN  1.212112 -0.173215  bar  False        NaT
e  0.119209 -1.044236 -0.861849  bar   True 2012-01-01
f -2.104569 -0.494929  1.071804  bar  False 2012-01-01
h       NaN -0.706771 -1.039575  bar   True        NaT

In [19]: df2.get_dtype_counts()
Out[19]: 
bool              1
datetime64[ns]    1
float64           3
object            1
dtype: int64

Inserting missing data

您可以通过简单地分配到容器来插入缺失值。使用的实际缺失值将基于dtype进行选择。

例如,无论选择的缺少值类型如何,数值型将始终使用NaN

In [20]: s = pd.Series([1, 2, 3])

In [21]: s.loc[0] = None

In [22]: s
Out[22]: 
0    NaN
1    2.0
2    3.0
dtype: float64

同样,datetime对象将始终使用NaT

对于object类型,pandas将使用给定的值:

In [23]: s = pd.Series(["a", "b", "c"])

In [24]: s.loc[0] = None

In [25]: s.loc[1] = np.nan

In [26]: s
Out[26]: 
0    None
1     NaN
2       c
dtype: object

Calculations with missing data

缺失值通过pandas对象之间的算术运算自然传播。

In [27]: a
Out[27]: 
        one       two
a       NaN -0.282863
c       NaN  1.212112
e  0.119209 -1.044236
f -2.104569 -0.494929
h -2.104569 -0.706771

In [28]: b
Out[28]: 
        one       two     three
a       NaN -0.282863 -1.509059
c       NaN  1.212112 -0.173215
e  0.119209 -1.044236 -0.861849
f -2.104569 -0.494929  1.071804
h       NaN -0.706771 -1.039575

In [29]: a + b
Out[29]: 
        one  three       two
a       NaN    NaN -0.565727
c       NaN    NaN  2.424224
e  0.238417    NaN -2.088472
f -4.209138    NaN -0.989859
h       NaN    NaN -1.413542

data structure overview(此处列出herehere)中讨论的描述性统计和计算方法都是为了记录丢失的数据。例如:

  • 当对数据求和时,NA(缺失)值将被视为零
  • 如果数据都是NA,则结果将是NA
  • cumsumcumprod等方法忽略NA值,但在生成的数组中保留它们
In [30]: df
Out[30]: 
        one       two     three
a       NaN -0.282863 -1.509059
c       NaN  1.212112 -0.173215
e  0.119209 -1.044236 -0.861849
f -2.104569 -0.494929  1.071804
h       NaN -0.706771 -1.039575

In [31]: df['one'].sum()
Out[31]: -1.9853605075978744

In [32]: df.mean(1)
Out[32]: 
a   -0.895961
c    0.519449
e   -0.595625
f   -0.509232
h   -0.873173
dtype: float64

In [33]: df.cumsum()
Out[33]: 
        one       two     three
a       NaN -0.282863 -1.509059
c       NaN  0.929249 -1.682273
e  0.119209 -0.114987 -2.544122
f -1.985361 -0.609917 -1.472318
h       NaN -1.316688 -2.511893

NA values in GroupBy

GroupBy中的NA组将自动排除。此行为与R一致,例如:

In [34]: df
Out[34]: 
        one       two     three
a       NaN -0.282863 -1.509059
c       NaN  1.212112 -0.173215
e  0.119209 -1.044236 -0.861849
f -2.104569 -0.494929  1.071804
h       NaN -0.706771 -1.039575

In [35]: df.groupby('one').mean()
Out[35]: 
                two     three
one                          
-2.104569 -0.494929  1.071804
 0.119209 -1.044236 -0.861849

有关详细信息,请参阅here部分。

Cleaning / filling missing data

pandas对象配备了各种数据处理方法来处理丢失的数据。

Filling missing values: fillna

fillna函数可以通过两种方式“填充”NA值与非空数据,我们说明:

将NA替换为标量值

In [36]: df2
Out[36]: 
        one       two     three four   five  timestamp
a       NaN -0.282863 -1.509059  bar   True        NaT
c       NaN  1.212112 -0.173215  bar  False        NaT
e  0.119209 -1.044236 -0.861849  bar   True 2012-01-01
f -2.104569 -0.494929  1.071804  bar  False 2012-01-01
h       NaN -0.706771 -1.039575  bar   True        NaT

In [37]: df2.fillna(0)
Out[37]: 
        one       two     three four   five  timestamp
a  0.000000 -0.282863 -1.509059  bar   True 1970-01-01
c  0.000000  1.212112 -0.173215  bar  False 1970-01-01
e  0.119209 -1.044236 -0.861849  bar   True 2012-01-01
f -2.104569 -0.494929  1.071804  bar  False 2012-01-01
h  0.000000 -0.706771 -1.039575  bar   True 1970-01-01

In [38]: df2['four'].fillna('missing')
Out[38]: 
a    bar
c    bar
e    bar
f    bar
h    bar
Name: four, dtype: object

向前或向后填充间隙

使用与reindexing相同的填充参数,我们可以向前或向后传播非空值:

In [39]: df
Out[39]: 
        one       two     three
a       NaN -0.282863 -1.509059
c       NaN  1.212112 -0.173215
e  0.119209 -1.044236 -0.861849
f -2.104569 -0.494929  1.071804
h       NaN -0.706771 -1.039575

In [40]: df.fillna(method='pad')
Out[40]: 
        one       two     three
a       NaN -0.282863 -1.509059
c       NaN  1.212112 -0.173215
e  0.119209 -1.044236 -0.861849
f -2.104569 -0.494929  1.071804
h -2.104569 -0.706771 -1.039575

控制填充的缺失值数量

如果我们只想让连续的间隙填充到一定数量的数据点,我们可以使用limit关键字:

In [41]: df
Out[41]: 
   one       two     three
a  NaN -0.282863 -1.509059
c  NaN  1.212112 -0.173215
e  NaN       NaN       NaN
f  NaN       NaN       NaN
h  NaN -0.706771 -1.039575

In [42]: df.fillna(method='pad', limit=1)
Out[42]: 
   one       two     three
a  NaN -0.282863 -1.509059
c  NaN  1.212112 -0.173215
e  NaN  1.212112 -0.173215
f  NaN       NaN       NaN
h  NaN -0.706771 -1.039575

为了提醒您,这些是可用的填充方法:

方法 行动
pad / ffill 向前填充值
bfill / backfill 向后填充值

使用时间序列数据,使用pad / ffill非常常见,因此“最后已知值”在每个时间点都可用。

ffill()函数等效于fillna(method='ffill')bfill()等效于fillna(method='bfill')

Filling with a PandasObject

版本0.12中的新功能。

你也可以使用可以对齐的dict或者系列。系列的dict或index的标签必须与您要填充的框架的列匹配。这种情况的用法是用该列的平均值填充DataFrame。

In [43]: dff = pd.DataFrame(np.random.randn(10,3), columns=list('ABC'))

In [44]: dff.iloc[3:5,0] = np.nan

In [45]: dff.iloc[4:6,1] = np.nan

In [46]: dff.iloc[5:8,2] = np.nan

In [47]: dff
Out[47]: 
          A         B         C
0  0.271860 -0.424972  0.567020
1  0.276232 -1.087401 -0.673690
2  0.113648 -1.478427  0.524988
3       NaN  0.577046 -1.715002
4       NaN       NaN -1.157892
5 -1.344312       NaN       NaN
6 -0.109050  1.643563       NaN
7  0.357021 -0.674600       NaN
8 -0.968914 -1.294524  0.413738
9  0.276662 -0.472035 -0.013960

In [48]: dff.fillna(dff.mean())
Out[48]: 
          A         B         C
0  0.271860 -0.424972  0.567020
1  0.276232 -1.087401 -0.673690
2  0.113648 -1.478427  0.524988
3 -0.140857  0.577046 -1.715002
4 -0.140857 -0.401419 -1.157892
5 -1.344312 -0.401419 -0.293543
6 -0.109050  1.643563 -0.293543
7  0.357021 -0.674600 -0.293543
8 -0.968914 -1.294524  0.413738
9  0.276662 -0.472035 -0.013960

In [49]: dff.fillna(dff.mean()['B':'C'])
Out[49]: 
          A         B         C
0  0.271860 -0.424972  0.567020
1  0.276232 -1.087401 -0.673690
2  0.113648 -1.478427  0.524988
3       NaN  0.577046 -1.715002
4       NaN -0.401419 -1.157892
5 -1.344312 -0.401419 -0.293543
6 -0.109050  1.643563 -0.293543
7  0.357021 -0.674600 -0.293543
8 -0.968914 -1.294524  0.413738
9  0.276662 -0.472035 -0.013960

版本0.13中的新功能。

与上面的结果相同,但是对齐了“fill”值,这是一个在这种情况下的系列。

In [50]: dff.where(pd.notnull(dff), dff.mean(), axis='columns')
Out[50]: 
          A         B         C
0  0.271860 -0.424972  0.567020
1  0.276232 -1.087401 -0.673690
2  0.113648 -1.478427  0.524988
3 -0.140857  0.577046 -1.715002
4 -0.140857 -0.401419 -1.157892
5 -1.344312 -0.401419 -0.293543
6 -0.109050  1.643563 -0.293543
7  0.357021 -0.674600 -0.293543
8 -0.968914 -1.294524  0.413738
9  0.276662 -0.472035 -0.013960

Dropping axis labels with missing data: dropna

您可能希望简单地从数据集中排除涉及缺失数据的标签。为此,请使用dropna方法:

In [51]: df
Out[51]: 
   one       two     three
a  NaN -0.282863 -1.509059
c  NaN  1.212112 -0.173215
e  NaN  0.000000  0.000000
f  NaN  0.000000  0.000000
h  NaN -0.706771 -1.039575

In [52]: df.dropna(axis=0)
Out[52]: 
Empty DataFrame
Columns: [one, two, three]
Index: []

In [53]: df.dropna(axis=1)
Out[53]: 
        two     three
a -0.282863 -1.509059
c  1.212112 -0.173215
e  0.000000  0.000000
f  0.000000  0.000000
h -0.706771 -1.039575

In [54]: df['one'].dropna()
Out[54]: Series([], Name: one, dtype: float64)

Series.dropna是一个更简单的方法,因为它只有一个轴要考虑。DataFrame.dropna有比Series.dropna更多的选项,可以在API中检查in the API

Interpolation

版本0.13.0中的新功能: interpolate()interpolate()更新了插值方法和功能。

版本0.17.0中的新功能:添加了limit_direction关键字参数。

Series和Dataframe对象都有一个interpolate方法,默认情况下,在缺失的数据点执行线性插值。

In [55]: ts
Out[55]: 
2000-01-31    0.469112
2000-02-29         NaN
2000-03-31         NaN
2000-04-28         NaN
2000-05-31         NaN
2000-06-30         NaN
2000-07-31         NaN
                ...   
2007-10-31   -3.305259
2007-11-30   -5.485119
2007-12-31   -6.854968
2008-01-31   -7.809176
2008-02-29   -6.346480
2008-03-31   -8.089641
2008-04-30   -8.916232
Freq: BM, dtype: float64

In [56]: ts.count()
Out[56]: 61

In [57]: ts.interpolate().count()
Out[57]: 100

In [58]: ts.interpolate().plot()
Out[58]: <matplotlib.axes._subplots.AxesSubplot at 0x7ff2667af150>
http://pandas.pydata.org/pandas-docs/version/0.19.2/_images/series_interpolate.png

可通过method关键字获得索引感知插值:

In [59]: ts2
Out[59]: 
2000-01-31    0.469112
2000-02-29         NaN
2002-07-31   -5.689738
2005-01-31         NaN
2008-04-30   -8.916232
dtype: float64

In [60]: ts2.interpolate()
Out[60]: 
2000-01-31    0.469112
2000-02-29   -2.610313
2002-07-31   -5.689738
2005-01-31   -7.302985
2008-04-30   -8.916232
dtype: float64

In [61]: ts2.interpolate(method='time')
Out[61]: 
2000-01-31    0.469112
2000-02-29    0.273272
2002-07-31   -5.689738
2005-01-31   -7.095568
2008-04-30   -8.916232
dtype: float64

对于浮点索引,请使用method='values'

In [62]: ser
Out[62]: 
0.0      0.0
1.0      NaN
10.0    10.0
dtype: float64

In [63]: ser.interpolate()
Out[63]: 
0.0      0.0
1.0      5.0
10.0    10.0
dtype: float64

In [64]: ser.interpolate(method='values')
Out[64]: 
0.0      0.0
1.0      1.0
10.0    10.0
dtype: float64

您还可以使用DataFrame插值:

In [65]: df = pd.DataFrame({'A': [1, 2.1, np.nan, 4.7, 5.6, 6.8],
   ....:                    'B': [.25, np.nan, np.nan, 4, 12.2, 14.4]})
   ....: 

In [66]: df
Out[66]: 
     A      B
0  1.0   0.25
1  2.1    NaN
2  NaN    NaN
3  4.7   4.00
4  5.6  12.20
5  6.8  14.40

In [67]: df.interpolate()
Out[67]: 
     A      B
0  1.0   0.25
1  2.1   1.50
2  3.4   2.75
3  4.7   4.00
4  5.6  12.20
5  6.8  14.40

method参数允许访问fancier插值方法。如果您安装了scipy,则可以将1-d插值程序的名称设置为method有关详细信息,请参阅完整的scipy插值文档和参考指南适当的插值方法将取决于您使用的数据类型。

  • 如果你正在处理一个以递增的速度增长的时间序列,则method='quadratic'可能是适当的。
  • 如果你有近似累积分布函数的值,那么method='pchip'应该工作得很好。
  • 要以平滑绘图的目标填充缺失值,请使用method='akima'

警告

这些方法需要scipy

In [68]: df.interpolate(method='barycentric')
Out[68]: 
      A       B
0  1.00   0.250
1  2.10  -7.660
2  3.53  -4.515
3  4.70   4.000
4  5.60  12.200
5  6.80  14.400

In [69]: df.interpolate(method='pchip')
Out[69]: 
         A          B
0  1.00000   0.250000
1  2.10000   0.672808
2  3.43454   1.928950
3  4.70000   4.000000
4  5.60000  12.200000
5  6.80000  14.400000

In [70]: df.interpolate(method='akima')
Out[70]: 
          A          B
0  1.000000   0.250000
1  2.100000  -0.873316
2  3.406667   0.320034
3  4.700000   4.000000
4  5.600000  12.200000
5  6.800000  14.400000

当通过多项式或样条逼近进行插值时,还必须指定近似的次数或次数:

In [71]: df.interpolate(method='spline', order=2)
Out[71]: 
          A          B
0  1.000000   0.250000
1  2.100000  -0.428598
2  3.404545   1.206900
3  4.700000   4.000000
4  5.600000  12.200000
5  6.800000  14.400000

In [72]: df.interpolate(method='polynomial', order=2)
Out[72]: 
          A          B
0  1.000000   0.250000
1  2.100000  -4.161538
2  3.547059  -2.911538
3  4.700000   4.000000
4  5.600000  12.200000
5  6.800000  14.400000

比较几种方法:

In [73]: np.random.seed(2)

In [74]: ser = pd.Series(np.arange(1, 10.1, .25)**2 + np.random.randn(37))

In [75]: bad = np.array([4, 13, 14, 15, 16, 17, 18, 20, 29])

In [76]: ser[bad] = np.nan

In [77]: methods = ['linear', 'quadratic', 'cubic']

In [78]: df = pd.DataFrame({m: ser.interpolate(method=m) for m in methods})

In [79]: df.plot()
Out[79]: <matplotlib.axes._subplots.AxesSubplot at 0x7ff2666771d0>
http://pandas.pydata.org/pandas-docs/version/0.19.2/_images/compare_interpolations.png

另一个用例是在值处的插值。假设你有一些分布的100个观察。让我们假设你对中间发生的事情特别感兴趣。您可以混合使用pandas'reindexinterpolate方法在新值处插值。

In [80]: ser = pd.Series(np.sort(np.random.uniform(size=100)))

# interpolate at new_index
In [81]: new_index = ser.index | pd.Index([49.25, 49.5, 49.75, 50.25, 50.5, 50.75])

In [82]: interp_s = ser.reindex(new_index).interpolate(method='pchip')

In [83]: interp_s[49:51]
Out[83]: 
49.00    0.471410
49.25    0.476841
49.50    0.481780
49.75    0.485998
50.00    0.489266
50.25    0.491814
50.50    0.493995
50.75    0.495763
51.00    0.497074
dtype: float64

Interpolation Limits

与其他Pandas填充方法一样,interpolate接受一个limit关键字参数。使用此参数限制连续插值的数量,对于距离上次有效观测值过远的插值,保留NaN值:

In [84]: ser = pd.Series([np.nan, np.nan, 5, np.nan, np.nan, np.nan, 13])

In [85]: ser.interpolate(limit=2)
Out[85]: 
0     NaN
1     NaN
2     5.0
3     7.0
4     9.0
5     NaN
6    13.0
dtype: float64

默认情况下,limit适用于正向,因此在非NaN值后只能填充NaN值。If you provide 'backward' or 'both' for the limit_direction keyword argument, you can fill NaN values before non-NaN values, or both before and after non-NaN values, respectively:

In [86]: ser.interpolate(limit=1)  # limit_direction == 'forward'
Out[86]: 
0     NaN
1     NaN
2     5.0
3     7.0
4     NaN
5     NaN
6    13.0
dtype: float64

In [87]: ser.interpolate(limit=1, limit_direction='backward')
Out[87]: 
0     NaN
1     5.0
2     5.0
3     NaN
4     NaN
5    11.0
6    13.0
dtype: float64

In [88]: ser.interpolate(limit=1, limit_direction='both')
Out[88]: 
0     NaN
1     5.0
2     5.0
3     7.0
4     NaN
5    11.0
6    13.0
dtype: float64

Replacing Generic Values

通常我们想用其他值替换任意值。v0.8中的新增功能是Series / DataFrame中的replace方法,它提供了一种高效而灵活的方法来执行此类替换。

对于系列,可以使用另一个值替换单个值或值列表:

In [89]: ser = pd.Series([0., 1., 2., 3., 4.])

In [90]: ser.replace(0, 5)
Out[90]: 
0    5.0
1    1.0
2    2.0
3    3.0
4    4.0
dtype: float64

您可以使用其他值列表替换值列表:

In [91]: ser.replace([0, 1, 2, 3, 4], [4, 3, 2, 1, 0])
Out[91]: 
0    4.0
1    3.0
2    2.0
3    1.0
4    0.0
dtype: float64

您还可以指定映射dict:

In [92]: ser.replace({0: 10, 1: 100})
Out[92]: 
0     10.0
1    100.0
2      2.0
3      3.0
4      4.0
dtype: float64

对于DataFrame,您可以按列指定单个值:

In [93]: df = pd.DataFrame({'a': [0, 1, 2, 3, 4], 'b': [5, 6, 7, 8, 9]})

In [94]: df.replace({'a': 0, 'b': 5}, 100)
Out[94]: 
     a    b
0  100  100
1    1    6
2    2    7
3    3    8
4    4    9

您可以将所有给定的值视为缺失并对其进行插值,而不是替换为指定的值:

In [95]: ser.replace([1, 2, 3], method='pad')
Out[95]: 
0    0.0
1    0.0
2    0.0
3    0.0
4    4.0
dtype: float64

String/Regular Expression Replacement

注意

r字符为前缀的Python字符串,如r'hello world'是所谓的“raw”字符串。他们有不同的反斜杠语义比没有这个前缀的字符串。原始字符串中的反斜杠将被解释为转义的反斜杠,例如r'\' == '\\' t0>。如果这不清楚,您应该阅读他们

nan(str - > str)替换'。'

In [96]: d = {'a': list(range(4)), 'b': list('ab..'), 'c': ['a', 'b', np.nan, 'd']}

In [97]: df = pd.DataFrame(d)

In [98]: df.replace('.', np.nan)
Out[98]: 
   a    b    c
0  0    a    a
1  1    b    b
2  2  NaN  NaN
3  3  NaN    d

现在使用正则表达式删除周围的空格(regex - > regex)

In [99]: df.replace(r'\s*\.\s*', np.nan, regex=True)
Out[99]: 
   a    b    c
0  0    a    a
1  1    b    b
2  2  NaN  NaN
3  3  NaN    d

替换几个不同的值(list - > list)

In [100]: df.replace(['a', '.'], ['b', np.nan])
Out[100]: 
   a    b    c
0  0    b    b
1  1    b    b
2  2  NaN  NaN
3  3  NaN    d

regex列表 - > regex列表

In [101]: df.replace([r'\.', r'(a)'], ['dot', '\1stuff'], regex=True)
Out[101]: 
   a       b       c
0  0  stuff  stuff
1  1       b       b
2  2     dot     NaN
3  3     dot       d

只搜索列'b'(dict - > dict)

In [102]: df.replace({'b': '.'}, {'b': np.nan})
Out[102]: 
   a    b    c
0  0    a    a
1  1    b    b
2  2  NaN  NaN
3  3  NaN    d

与上一个示例相同,但使用正则表达式进行搜索(dict的regex - > dict)

In [103]: df.replace({'b': r'\s*\.\s*'}, {'b': np.nan}, regex=True)
Out[103]: 
   a    b    c
0  0    a    a
1  1    b    b
2  2  NaN  NaN
3  3  NaN    d

您可以传递使用regex=True的正则表达式的嵌套字典

In [104]: df.replace({'b': {'b': r''}}, regex=True)
Out[104]: 
   a  b    c
0  0  a    a
1  1       b
2  2  .  NaN
3  3  .    d

或者你可以像这样传递嵌套字典

In [105]: df.replace(regex={'b': {r'\s*\.\s*': np.nan}})
Out[105]: 
   a    b    c
0  0    a    a
1  1    b    b
2  2  NaN  NaN
3  3  NaN    d

你也可以在替换时使用正则表达式匹配的组(正则表达式的dict - >正则表达式的dict),这也适用于列表

In [106]: df.replace({'b': r'\s*(\.)\s*'}, {'b': r'\1ty'}, regex=True)
Out[106]: 
   a    b    c
0  0    a    a
1  1    b    b
2  2  .ty  NaN
3  3  .ty    d

您可以传递正则表达式列表,其中匹配的那些将被替换为标量(regex - > regex列表)

In [107]: df.replace([r'\s*\.\s*', r'a|b'], np.nan, regex=True)
Out[107]: 
   a   b    c
0  0 NaN  NaN
1  1 NaN  NaN
2  2 NaN  NaN
3  3 NaN    d

所有正则表达式示例也可以使用to_replace参数作为regex参数传递。在这种情况下,value参数必须通过名称显式传递,或regex必须是嵌套字典。在这种情况下,上一个示例将是

In [108]: df.replace(regex=[r'\s*\.\s*', r'a|b'], value=np.nan)
Out[108]: 
   a   b    c
0  0 NaN  NaN
1  1 NaN  NaN
2  2 NaN  NaN
3  3 NaN    d

如果您不想在每次要使用正则表达式时传递regex=True,这都很方便。

注意

在上述replace示例的任何地方,您看到正则表达式编译的正则表达式也是有效的。

Numeric Replacement

类似于DataFrame.fillna

In [109]: df = pd.DataFrame(np.random.randn(10, 2))

In [110]: df[np.random.rand(df.shape[0]) > 0.5] = 1.5

In [111]: df.replace(1.5, np.nan)
Out[111]: 
          0         1
0 -0.844214 -1.021415
1  0.432396 -0.323580
2  0.423825  0.799180
3  1.262614  0.751965
4       NaN       NaN
5       NaN       NaN
6 -0.498174 -1.060799
7  0.591667 -0.183257
8  1.019855 -1.482465
9       NaN       NaN

通过列表替换多个值也是如此

In [112]: df00 = df.values[0, 0]

In [113]: df.replace([1.5, df00], [np.nan, 'a'])
Out[113]: 
          0         1
0         a -1.021415
1  0.432396 -0.323580
2  0.423825  0.799180
3   1.26261  0.751965
4       NaN       NaN
5       NaN       NaN
6 -0.498174 -1.060799
7  0.591667 -0.183257
8   1.01985 -1.482465
9       NaN       NaN

In [114]: df[1].dtype
Out[114]: dtype('float64')

你也可以在DataFrame上操作

In [115]: df.replace(1.5, np.nan, inplace=True)

警告

替换多个booldatetime64对象时,replaceto_replace)的第一个参数必须匹配值为替换类型。例如,

s = pd.Series([True, False, True])
s.replace({'a string': 'new value', True: False})  # raises

TypeError: Cannot compare types 'ndarray(dtype=bool)' and 'str'

将会产生TypeError,因为dict键之一不是用于替换的正确类型。

但是,当替换单个对象时,

In [116]: s = pd.Series([True, False, True])

In [117]: s.replace('a string', 'another string')
Out[117]: 
0     True
1    False
2     True
dtype: bool

原始的NDFrame对象将不被触摸。我们正在努力统一这个API,但是出于向后兼容性的原因,我们不能打破后面的行为。有关详细信息,请参阅GH6354

Missing data casting rules and indexing

虽然pandas支持存储整数和布尔类型的数组,但这些类型不能存储缺失的数据。直到我们可以在NumPy中切换到使用本地NA类型,我们已经建立了一些“转换规则”,当重建索引将导致丢失的数据被引入,例如,一个Series或DataFrame。他们来了:

数据类型 投放到
整数 浮动
布尔 目的
浮动 没有演员
目的 没有演员

例如:

In [118]: s = pd.Series(np.random.randn(5), index=[0, 2, 4, 6, 7])

In [119]: s > 0
Out[119]: 
0    True
2    True
4    True
6    True
7    True
dtype: bool

In [120]: (s > 0).dtype
Out[120]: dtype('bool')

In [121]: crit = (s > 0).reindex(list(range(8)))

In [122]: crit
Out[122]: 
0    True
1     NaN
2    True
3     NaN
4    True
5     NaN
6    True
7    True
dtype: object

In [123]: crit.dtype
Out[123]: dtype('O')

如果您尝试使用对象数组(即使它包含布尔值)而不是布尔数组来从ndarray获取或设置值(例如,根据某些条件选择值),NumPy通常会提示。如果布尔向量包含NA,将生成异常:

In [124]: reindexed = s.reindex(list(range(8))).fillna(0)

In [125]: reindexed[crit]
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-125-2da204ed1ac7> in <module>()
----> 1 reindexed[crit]

/home/joris/scipy/pandas/pandas/core/series.pyc in __getitem__(self, key)
    639             key = list(key)
    640 
--> 641         if com.is_bool_indexer(key):
    642             key = check_bool_indexer(self.index, key)
    643 

/home/joris/scipy/pandas/pandas/core/common.pyc in is_bool_indexer(key)
    199             if not lib.is_bool_array(key):
    200                 if isnull(key).any():
--> 201                     raise ValueError('cannot index with vector containing '
    202                                      'NA / NaN values')
    203                 return False

ValueError: cannot index with vector containing NA / NaN values

但是,这些可以使用fillna填充,它会工作正常:

In [126]: reindexed[crit.fillna(False)]
Out[126]: 
0    0.126504
2    0.696198
4    0.697416
6    0.601516
7    0.003659
dtype: float64

In [127]: reindexed[crit.fillna(True)]
Out[127]: 
0    0.126504
1    0.000000
2    0.696198
3    0.000000
4    0.697416
5    0.000000
6    0.601516
7    0.003659
dtype: float64
Scroll To Top