现有两个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"
网友评论