在Pandas图中标记插值的NaN点

时间:2015-08-02 17:35:22

标签: python pandas matplotlib plot data-visualization

当我在Pandas中使用插值(或fillna或任何其他生成某些假数据的方法)时,我希望在我的图中显示。理想情况下,我想在图中为这些点使用不同的标记。对于常规点我想使用实心圆('o'),对于假数据我想使用十字('x')。

当然,我想用漂亮的Pythonic oneliner做到这一点。

另一个复杂因素是我想在绘图函数中使用subplots选项一次绘制所有列。我希望用Matplotlib操纵子图是不必要的,尽管此时这是我能想到的唯一选择。

我正在使用的数据类似于以下内容(放入文件'metertanden.ssv'):

datum       tijd   gas[m^3]   electra1[kWh] electra2[kWh]  water[m^3]
2015-03-06  09:00  4000.318   10300         9000           300.0
2015-03-24  20:10  4020.220   -             10003          -
2015-08-02  11:15  4120.388   10500         11000          350.5

这是我用来处理它的脚本:

import matplotlib.pyplot as plt
import pandas as pd

df = pd.read_table("meterstanden.ssv", delim_whitespace=True,
                   parse_dates=[[0, 1]], index_col=0, na_values=['-'])

df.interpolate(method='time').plot(subplots=True, layout=(2, 2),
                                   figsize=(14, 10), marker='o')
plt.show()

我希望表中的-条目用交叉标记绘制。

3 个答案:

答案 0 :(得分:3)

我无法想出pythonic单线,但也许这样做。 (使用散点图你会有更多的选择,比如使用s kwarg,虽然我不确定它最终会比这个解决方案更好。)

np.random.seed(123)
df=pd.DataFrame({ 'x':np.random.choice([1,2,np.nan],20),
                  'y':np.random.choice([3,4,np.nan],20) },
                  index=pd.date_range('2015-1-1',periods=20) )

我认为无论采用何种确切的方法,都需要设置两个数据帧,这些数据帧在包含估算值方面有所不同。我会这样做的。

mask=df.isnull()
df=df.interpolate(method='time')
imputed=df[mask]

然后,这只是覆盖两个线图的问题。一个正常完成,但第二个没有线,只包括推算值。您不关心来自插补值的连接线,但您确实希望看到这些点,因此您可以为它们提供区分标记。我正在按你的要求使用'o'而不是'x',因为'o'显示得更清楚,但你当然可以改变它。

for c in df.columns:
    plt.plot(df[c])
    plt.plot(imputed[c],linestyle='',marker='o')
    plt.show()

enter image description here

enter image description here

您还可以考虑使用线条颜色来传达有关图表的哪些部分基于估算值的信息。有几种方法可以做到这一点,这是一个。

not_imp=df[~mask]

for c in df.columns:
    plt.plot(df[c],color='r')
    plt.plot(not_imp[c],color='b',marker='o')
    plt.plot(imputed[c],color='r',marker='d',linestyle='')
    plt.show()

所以这里发生的是蓝色(圆圈)标记表示真实(非插曲)值,蓝线表示真实与真实。红色(菱形)标记表示插补值,红线表示插补值与其他插补值或实际值相关联。

enter image description here

enter image description here

答案 1 :(得分:1)

有趣。据我所知,没有一种巧妙的方法可以利用layout=函数中的subplots=pandas.DataFrame.plot选项来做你想做的事情。 The docs在这方面不要说太多。

我的尝试

首先我做了一些测试数据

df1 = pandas.DataFrame({'D':np.random.random(150) , 
                        'A':np.random.random(150),
                        'B':np.random.random(150), 
                        'C':np.random.random(150)})
df1[ df1 > 0.8] = np.nan
df1[ df1 < 0.1] = '-'

接下来,您要填充NaN以便绘制它们,我通过制作单独的数据框来完成此操作,原始NaN值设置为某个值,其他所有设置为{{ 1}}:

NaN

对于# fill na with a lucky number df2 = df1.fillna( 0.777) df2[df2 != 0.777] = np.nan 标记,我将它们设置为某个值(您可能希望将它们设置为相应列的平均值或其他值),然后将其他所有内容设置为'-':< / p>

np.nan

现在,我试图绘制每个数据帧

#Similarly,  fill the '-' with another number
df3 = df1.copy()
df3[ df3 != '-'] = np.nan
df3[ df3 == '-'] = 0.5

# finally convert non-numerics to np.nan
df1[ df1=='-'] = np.nan

这使得以下3个数字 enter image description here enter image description here enter image description here ,这不是你想要的。

直接使用pylab的替代方法

采用上面的原始数据帧,您可以直接利用pylab(从未如此轻微)来完成您可能喜欢的事情:

# make plot options for each dataframe
opts =  ({ 'marker':'o' ,'color':'b', 'title':'data' },
        {'marker':'d', 'color':'g','title':'NaN' }, 
        {'marker':'x', 'color':'r','title':'"-" values'} )
dfs  = (df1,df2,df3 )
for opt,df in zip( opts, dfs ):
    df.plot( subplots=True, layout=(2,2), **opt)
plt.show()

这产生了以下enter image description here

答案 2 :(得分:0)

这是一个旧帖子,但以下有效:

missing_df = df_ip.mask(df.notnull())