美文网首页我爱编程
pandas dataframe 运算问题

pandas dataframe 运算问题

作者: 11的雾 | 来源:发表于2018-05-21 18:19 被阅读0次

    现有两个dataframe,


    dataframe1

    这个datafram1 每一行算了一个平均值,
    每一行算一个标准差。

    有另外一个dataframe2,也是类似的表格。行数与第一个是一致的,列数不一定一致。


    dataframe2

    现在需要将dataframe2 中的每个值按照对应的行 去减去第一个表算出来的平均值再除以第一个表里的标准差。(运算时,行必须一一对应),最后得到一个最终的表。

    其实就是算一个z值,z=(观测值-平均值)/标准差
    解释:
    第一个表相当于标准集,用标准集里的数据算出来平均值和标准差,第二个表是真实测量的值,用来做t检验。
    算了一个z score。
    在excel里很好实现。但是在用python pandas实现的时候遇到了问题。

    解决方案:
    1,将平均值和标准差的列转换成numpy的array:np.array(‘Series_name’, dtype=pd.Series)
    2,再用data.reshape(),将格式转过来。
    3,将dataframe也转成array格式,newdata = np.array(tmp3,dtype=pd.DataFrame)
    4,相互运算。
    其实这部分可以仔细阅读利用《利用python进行数据分析》一书的第11章“广播”章节。会有详细的解释不同形状的数组之间的运算的执行方式。


    部分截图
    截图2

    代码如下

    #! coding:utf-8
    import sys
    import pandas as pd
    import numpy as np
    # 读取内参文件
    data = pd.read_table(sys.argv[1],sep="\t",index_col='Region')
    # data = np.loadtxt(sys.argv[1],dtype=np.str,delimiter=None,index_col='Region')
    
    # 先归一化:将数据除以每一列的总和。得到百分比。
    norma_data = data/data.sum(axis=0)
    # 求平均数和标准差
    tmp1 = norma_data.mean(axis=1)
    average = np.array(tmp1, dtype=pd.Series)
    average = average.reshape(47,1)
    # 标准差
    tmp2 = norma_data.std(axis=1)
    std = np.array(tmp2,dtype=pd.Series)
    std = std.reshape(47,1)
    # 读取观测值文件
    observed_data = pd.read_table(sys.argv[2],sep="\t",index_col='Region',na_values=False)
    # dropna
    observed_data = observed_data.dropna(axis=1)
    tmp3 = observed_data/observed_data.sum(axis=0)
    # convert pd DataFrame to np array.
    newdata = np.array(tmp3,dtype=pd.DataFrame)
    # 计算 z-score
    outdata = (newdata - average)/std
    print outdata
    

    那么问题又来了,输出时候如何添加index?
    解决方法:将np再转回成pd的dataframe,并添加了index和columns

    # convert np.array to pd.DataFrame
    outdata = pd.DataFrame(outdata,index=observed_data.index,columns=observed_data.columns)
    

    输出:两种方式:如果数据是np.array,就用np.savetxt(),如果数据格式是pd.dataframe,就用to_csv().

    np.savetxt(sys.stdout,outdata,fmt='%.4f',delimiter="\t")
    outdata.to_csv(sys.stdout,sep="\t",index=True,header=True) # this is pandas format.
    

    然后画图:

    import matplotlib.pyplot as plt
    fig = plt.figure(figsize=(25,25))
    
    '''
    this is a test sample.
    plt.subplot()
    x=[1,2,3,4,5,6,7,8,9,10]
    y=[6.5,6.5,6.2,14,6.8,6.9,6.3,6.7,6.4,6.4]
    plt.scatter(x,y)
    '''
    for i in range(outdata.columns.size):
        # 因为我有87个观测值,所以这里需要9x10个subplot.这里设置应该由输入样本的列自动判断。通过设置开方运算并向上取整和向下取整得到两个值
        plt.subplot(int(math.ceil(math.sqrt(outdata.columns.size))),int(math.floor(math.sqrt(outdata.columns.size))),1+i) 
        # print select
        # 画图 横坐标是行数,纵坐标是
        plt.scatter(range(len(outdata.iloc[:,i])),outdata.iloc[:,i],marker=".",)
        # 设置x和y轴的范围
        plt.xlim((0,50))
        plt.ylim((-8,8))
        plt.title(outdata.columns[i],loc='center',fontsize='xx-small')
        # plt.text(outdata.columns[i],loc='top')
    # 设置布局
    # plt.tight_layout()
    # 保存图片到本地
    plt.savefig("scatter.png")
    # show figer in screen
    # plt.show()
    
    scatter.png

    那么问题又来啦:如何根据数据中值的大小改变点的颜色呢?找了很久没找到解决方案,只能用如下筛选的方法将其筛选出来,存在文本中再看。

    dataframe的条件选择:循环遍历行或列,并根据值输出相应的index或索引。

    # select data
    for index, row in outdata.iterrows():
        # for each in row:
        for col_name in outdata.columns:
            # if each >3 :
            if abs(row[col_name]) > 3:
                print index,col_name,row[col_name]
    

    数据描述 describe()可以将得到数据的一些基本信息:

    print norma_data.describe()
    >>>
           barcode_37.1  barcode_40.1  barcode_41.1  barcode_44.1  barcode_45.1
    count     47.000000     47.000000     47.000000     47.000000     47.000000
    mean       0.021277      0.021277      0.021277      0.021277      0.021277
    std        0.008892      0.009033      0.009333      0.008836      0.008652
    min        0.006885      0.006420      0.006484      0.006383      0.006561
    25%        0.014518      0.013792      0.014353      0.014279      0.014847
    50%        0.019986      0.019670      0.019693      0.019967      0.020826
    75%        0.026204      0.026191      0.025343      0.027033      0.027387
    max        0.040870      0.039010      0.041920      0.039573      0.038550
    
    

    通过四分位法筛选离群值:
    步骤:
    1,dataframe中先算出来每列的四分位Q1,Q3
    2,再算IQR = Q3-Q1
    3,再算外线 outlier_step = 1.5 * IQR
    4,再筛选,将大于上线和小于下线的值更改为NAN:

    data = pd.read_table(sys.argv[1],sep="\t",index_col='Region')
    # data = np.loadtxt(sys.argv[1],dtype=np.str,delimiter=None,index_col='Region')
    
    # 先归一化:将数据除以每一列的总和。得到百分比。
    norma_data = data/data.sum(axis=0)
    #将归一化的数据中的每一行异常值去掉。采用四分位法: 
    Q1 = np.percentile(norma_data, 25,axis=1)
    Q3 = np.percentile(norma_data,75,axis=1)
    IQR = Q3 - Q1
    outlier_step = 1.5 * IQR
    high_limits = Q3 + outlier_step
    low_limits  = Q1 - outlier_step
    # need reshape from list to array.
    high_limits = high_limits.reshape(norma_data.index.size,1)
    low_limits  =  low_limits.reshape(norma_data.index.size,1)
    # conver np to pd format
    high_limits = pd.DataFrame(high_limits,columns=["high_limits"],index=data.index)
    low_limits = pd.DataFrame(low_limits,columns=["low_limits"],index=data.index)
    # 修改异常值为NAN
    for index,row in norma_data.iterrows():
        for col_name in norma_data.columns:
            if row[col_name] > high_limits.loc[index,'high_limits'] or row[col_name] < low_limits.loc[index,'low_limits'] :
                print low_limits.loc[index,'low_limits'], row[col_name],high_limits.loc[index,'high_limits']
                row[col_name] = "NaN"
    
    

    相关文章

      网友评论

        本文标题:pandas dataframe 运算问题

        本文链接:https://www.haomeiwen.com/subject/kosqjftx.html