Python包-pandas

官方资料

api参考文档
官方文档-en
官方文档-cn
pandas的 General functions
盖若pandas速查

方法 简介 示例
concat Concatenate pandas objects along a particular axis with optional set logic along the other axes. df_result = pd.concat([dataframe1 , dataframe2])

常用功能及代码块示例

得到一个DataFrame

创建一个空的dataframe

1
2
3
4
#指定dataframe的所有字段
columns=["sampleName","#Gene","Transcript,"cHGVS","pHGVS","Frequence"]
#创建一个含字段结构的空数据框
DF = pd.DataFrame(columns=columns)

从文件中读取一个dataframe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 读取Excel
DF = pd.read_excel(file, sheet_name=None)
DF = pd.read_csv(file,sep="\t" )
# sheet_name 指定 None时,读取所有sheet返回一个字典,key为sheet名; 不指定默认读取第一个sheet)

# 读取tsv文件
pd.read_csv(filename, sep="\t")

# 读取压缩文件
df = pd.read_csv('filename.zip')

# 指定压缩格式
df = pd.read_csv('filename.zip', compression='zip', header=0, sep=',', quotechar='"')
压缩:{'infer','gzip','bz2','zip','xz',无},默认为'infer'用于对磁盘数据进行实时解压缩。如果'infer'和filepath_or_buffer与路径类似,则从以下扩展名检测压缩:'.gz','。bz2','。zip'或'.xz'(否则不进行解压缩)。如果使用“ zip”,则ZIP文件必须仅包含一个要读取的数据文件。设置为“无”将不进行解压缩。

读取数据时跳过注释信息

在我们实际使用的文件,尤其是一些数据库类型的记录文件中,通过添加注释,文件通常可以更加清晰明了。csv文件中有注释,这种情况是可能存在的。那么,在pandas读取csv文件的时候,如何规避掉注释。

1
2
3
4
5
6
7
8
9
10
11
12
#empty
a,b,c
12,中国,上海

# 如果仅指定分隔符,正常读取是不合理的,结果仅有一列而非a,b,c三列,注释当做了列名
>>> df = pd.read_csv('D:/1.csv', sep=' ')
>>> df
#empty\na,b,c\n1,2,3
a b c
12 中国 上海
>>> df.columns
Index(['#empty\na,b,c\n1,2,3'], dtype='object')

我们可以通过设置comment参数,指定某一行是注释,则该行就不会被解析

1
2
3
4
>>> df = pd.read_csv('D:/1.csv', sep=' ', comment='#')
>>> df
a b c
0 12 中国 上海

获取DataFrame的信息

查看头尾数据

1
2
3
4
5
6
# 查看开头的N(默认值5) 行
df.head()
# 查看开头的10行
df.head(10)
# 查看结尾的N(默认值5) 行
df.tail()

随机查看数据

1
2
# 随机查看N(默认1 )行数据
df.sample(N)

逐行读取dataframe的每行

DataFrame.iterrows()
1
2
for index, row in df.iterrows():
print row["c1"], row["c2"]
DataFrame.itertuples()
1
2
3
4
for row in df.itertuples(index=True, name='Pandas'):
print getattr(row, "c1"), getattr(row, "c2")
# 取值方式 -
print(row.c1)

itertuples()应该比iterrows()快

获取指定cell的数据信息 iloc

1
2
3
4
5
6
# 获取第i行,c1字段的内容
df.iloc[i]['c1']

#也可以通过遍历index获取全部行的特定信息列
for i in range(0, len(df)):
print df.iloc[i]['c1'], df.iloc[i]['c2']
将DataFrame转为List

略麻烦,但是更高效,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from collections import namedtuple

def myiter(d, cols=None):
if cols is None:
v = d.values.tolist()
cols = d.columns.values.tolist()
else:
j = [d.columns.get_loc(c) for c in cols]
v = d.values[:, j].tolist()

n = namedtuple('MyTuple', cols)

for line in iter(v):
yield n(*line)

筛选DataFrame的数据

单个条件筛选

1
2
3
4
5
6
7
8
9
10
$ print(df)
name age sex
Tim 10 男
Sam 20 女
Tom 30 NaN

$ df[df["age"]>15]
name age sex
Sam 20 女
Tom 30 NaN

多个条件筛选

存在多个比较条件的时候,需要注意

  • 多个条件同时满足不能用and,使用 &
  • 多个条件满足其中一个即可,不能使用or,使用 |
  • 每个条件要使用 小括号
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ print(df)
    name age sex
    Tim 10 男
    Sam 20 女
    Tom 30 NaN

    $ df[(df["age"]>15) & (df["age"]<25>)]
    name age sex
    Sam 20 女

筛选常用的数值函数

1
2
3
4
5
6
df.eq()    # 等于相等 ==
df.ne() # 不等于 !=
df.le() # 小于等于 >=
df.lt() # 小于 <
df.ge() # 大于等于 >=
df.gt() # 大于 >
  • 使用单个数值函数筛选
    1
    2
    3
    $ df[(df["age"] eq 20)]
    name age sex
    Sam 20 女

筛选常用的字符型函数

1
2
3
包含:str.contains
开始:str.startswith
结束:str.endswith

示例如下:

1
2
3
4
5
6
7
8
$ df[(df["name"].str.contains("o"))]
name age sex
Tom 30 NaN

# 如果字符串所在列存在空值,则可以通过添加参数进行剔除,否则报错
$ df[(df["sex"].str.contains("男",na=False))]
name age sex
Tim 10 男

基于索引筛选

情况比较少,但是特殊情况也会用到

1
2
$ df[df.index == 1]
Sam 20 女

筛选存在缺失值的行

1
2
3
$ df[df.isnull().values==True]
name age sex
Tom 30 NaN

更强自定义化的筛选

定义一个函数,进行复杂的逻辑判断;使用apply对dataframe进行系统化批量的处理

1
2
3
4
5
6
7
8
9
def checkfunction(x,y,z):
if int(x) >= 100:
if y in ('*', '-'):
return True
elif int(y) >= 1 and int(z) >= 1:
return True
return False

FilterData = RawData[RawData.apply(lambda x: checkfunction(x["tag_x"],x["tag_y"],x["tag_z"]), axis=1)]

更改 dataframe 的内容

整个dataframe的全局替换

1
2
3
4
5
# 将所有na替换为特定的values
data.fillna(value=values,inplace=True)

# 通过使用正则进行文本的全局替换
data.replace("\r\n","<br>",regex=True,inplace=True) # 将数据中的换行符统一替换成 <br> .regex:是否使用正则,若不适用,则只能进行整体的替换。

整列改为相同的值

1
DF['sampleName'] = "S1" # 将数据框DF的sampleName列都改为 "S1"

根据特定条件修改某一列的值

调用DataFrame.apply()方法,可以作用于 Series 或者整个 DataFrame,它自动遍历整个 Series 或者 DataFrame, 对每一个元素运行指定的函数。
更改前最好对数据进行确认,如果在数据中不存在满足条件的记录,导致更改操作处理的是一个空的dataframe 会导致报错

1
2
3
4
5
6
7
8
9
10
11
12
# 使用lambda函数进行操作
df['label']=df.id.apply(lambda x: 1 if 'M' in x else 0)

# 使用预定义的函数进行处理
def valuation_formula(x, y):
return x * y * 0.5
df['price'] = df.apply(lambda row: valuation_formula(row['x'], row['y']), axis=1)

# 如果id列值包含‘L’,那么就将label列中对应的值从1替换成0:
# 先判断是否存在满足条件的数据记录,如果有在进行更改
if len(df[df['id'].str.contains('L')]) > 0:
df.loc[df['id'].str.contains('L'),'label']=0

根据特定条件修改某几列的值

前面介绍了基于dataframe的某几列,更新某一列的值。但是实际使用中,我们也会遇到基于某几列信息,更新dataframe中的某几列值。
这时候,一种方案是每一列值都单独进行更新迭代,但是如果这些结果每次都需要运行获取相关结果,所以显而易见的会显著提升分析耗时(可以使用一些函数的缓存加速方案进行优化)。
所以在这提供一个基于几列内容和一个逻辑函数,对dataframe的多列进行更新的示例代码

1
2
3
4
5
6
7
8
9
10
# 分布更改
ReturnData['BGI_Uniport_Position(s)']=ReturnData.apply(lambda row: self.check(row['Hugo_Symbol'],row['HGVSp_Short'])[0],axis=1)
ReturnData['BGI_Uniport_feature_key']=ReturnData.apply(lambda row: self.check(row['Hugo_Symbol'],row['HGVSp_Short'])[1],axis=1)
ReturnData['BGI_Uniport_description']=ReturnData.apply(lambda row: self.check(row['Hugo_Symbol'],row['HGVSp_Short'])[2],axis=1)

# 一次更新多个字段
# check处理函数返回值如下
# return BGI_Uniport_Position,BGI_Uniport_feature_key,BGI_Uniport_description
ReturnData[['BGI_Uniport_Position(s)','BGI_Uniport_feature_key','BGI_Uniport_description']]=ReturnData.apply(lambda row: pd.Series(self.check(row['Hugo_Symbol'],row['HGVSp_Short'])),axis=1)
# ps 由于函数返回的是一个元祖,所以需要使用 pd.Series 讲元祖拆分成三列,然后分别赋值给Dataframe的相应列。

更新DataFrame某一列(值位于另一个DataFrame)

1
2
3
4
5
6
7
8
import pandas as pd

df1=pd.DataFrame({'id':[1,2,3],'name':['Andy1','Jacky1','Bruce1']})
df2=pd.DataFrame({'id':[1,2],'name':['Andy2','Jacky2']})

s = df2.set_index('id')['name']
df1['name'] = df1['id'].map(s).fillna(df1['name']).astype(str)
print(df1)

将dataframe中的某一列中的文本拆分成多行

示例:
image

1
2
3
df=df.drop('cont', axis=1).join(df['cont'].str.split('/', expand=True).stack().reset_index(level=1, drop=True).rename('tag'))

df=df['cont'].str.split('/', expand=True).stack().reset_index(level=0).set_index('level_0').rename(columns={0:'tag'}).join(df.drop('cont', axis=1))

将dataframe中的多列合并成一个新列

1
2
3
4
5
6
7
8
9
10
11
12
13
data
#GENE1 GENE2 chr pos
RPN2 SRC chr20 35868878
LINC00486 PLXNA1 chr2 33141303
LINC00486 TRRAP chr2 33141470
LINC00486 MAPK3 chr2 33141307

data["chr_pos"] = data['chr'].str.cat(data.pos.astype('str'),sep=":")
#GENE1 GENE2 chr pos chr_pos
RPN2 SRC chr20 35868878 chr20:35868878
LINC00486 PLXNA1 chr2 33141303 chr2:33141303
LINC00486 TRRAP chr2 33141470 chr2:33141470
LINC00486 MAPK3 chr2 33141307 chr2:33141307

dataframe的合并

按列进行合并

  • merge (着重关注的是行的合并)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    >>> print(df1)
    Courses Fee Duration
    r1 Spark 20000 30days
    r2 PySpark 25000 40days
    r3 Python 22000 35days
    r4 pandas 30000 50days
    >>> print(df2)
    Courses Discount
    r1 Spark 2000
    r6 Java 2300
    r3 Python 1200
    r5 Go 2000

    # pandas.merge()
    df3=pd.merge(df1,df2, how='left')
    print(df3)

    # DataFrame.merge()
    df3=df1.merge(df2, how='left')
    print(df3)

    Courses Fee Duration Discount
    0 Spark 20000 30days 2000.0
    1 PySpark 25000 40days NaN
    2 Python 22000 35days 1200.0
    3 pandas 30000 50days NaN

    # 按特定的列进行两个dataframe的合并
    # Merge DataFrames by Columns
    df3=pd.merge(df1,df2, on='Courses', how='left')

    # When column names are different
    df3=pd.merge(df1,df2, left_on='Courses', right_on='Courses', how='left')
    print(df3)

    # 其中how参数游四个选项
    how="inner"
    # inner是merge函数的默认参数,意思是将dataframe_1和dataframe_2两表中主键一致的行保留下来,然后合并列。

    how="outer"
    # outer是相对于inner来说的,outer不会仅仅保留主键一致的行,还会将不一致的部分填充Nan然后保留下来。

    how="left" || how="right"
    # 然后是left和right,首先为什么是left和right,left指代的是输入的时候左边的表格即dataframe_1,同理right指代dataframe_2。
    # left和right相当于inner和outer取了个折中的合并方法,意为保证dataframe_1或者dataframe_2不变(不变的表格我们这里记为目标表格),然后另一个表格(我们这里记为信息表格)向目标表格添加信息。

按行进行拼接

1
2
# 将两个dataframe逐行添加
df_result = pd.concat([dataframe1 , dataframe2])

dataframe中逐行添加数据

1
AllSampleFastqQC.loc[len(AllSampleFastqQC)+1] = [SampleDir,SampleDirPath,Chip,lane,barcode,umi,Q20,Q30,GC]

dataframe 去重

drop_duplicates()函数的语法格式如下:

1
2
3
4
df.drop_duplicates(subset=['A','B','C'],keep='first',inplace=True)
#subset:表示要进去重的列名,默认为 None。
#keep:有三个可选参数,分别是 first、last、False,默认为 first,表示只保留第一次出现的重复项,删除其余重复项,last 表示只保留最后一次出现的重复项,False 则表示删除所有重复项。
#inplace:布尔值参数,默认为 False 表示删除重复项后返回一个副本,若为 Ture 则表示直接在原数据上删除重复项。

-------------本文结束感谢您的阅读-------------