本文对pandas模块的一些核心概念进行说明。
基本入门
pandas最核心的两个数据结构就是 Series 类和 DataFrame 类。其中DataFrame可能会用的偏多一点,Series相当于一维情况下较简单的DataFrame,有的时候会用到。本文重点讨论DataFrame类。
DataFrame之所以很常用是因为这种数据结构太常见了,在excel中,在csv中,在sql中,等等来源的数据都可以汇总成为DataFrame数据结构,然后进行一些后面必要的数据处理,包括送入机器学习或者深度学习的模型中去。
读写文件支持
pandas的io子模块写得很便捷,实际上我经常看到有些python程序员并不是在做数据处理,有时都会调用下pandas的io来做一些读写操作。
其大体有这些函数:
- read_csv to_csv
- read_json to_json
- read_html to_html
- read_excel to_excel
- read_sql to_sql
这其中,html的读写在网络抓取上有时可能有用,但不是很强大,还是推荐用专门的工具来做,sql的操作简单点可以用pandas那边的接口,但如果稍微复杂点还是推荐用sqlalchemy来做,这样写出来的代码可读性更好一些,orm层接口也更便捷写,代码里面全是一大堆sql语句,总不是太好的。
读csv文件
实际上我们可能更常遇到的是txt文件,还是用 read_csv 函数来读,只是需要做一些额外的配置,比如 这个问题 里面的例子是这样的:
data = pd.read_csv('output_list.txt', sep=" ", header=None)
- sep 设置读取csv时每个字段的分隔,默认是逗号,我遇到过是
\t
作为分隔符的情况 - header 默认取csv的第一行作为df数据的作为各个列的列名,如果设置了
names
,也就是手动指定列名,那么header相当于设置了None,如果header设置了None,将不会读取第一行作为列名。
read_csv 有很多选项,应付初步加载csv数据进入df内是绝对没问题的了。
读excel文件
利用pd.read_excel来读excel文件里面的数据,这个功能需要安装 xlrd 模块。
读取html网页
读取html网页具体就是分析网页里面的table标签所在,然后刷table并将数据填充到df里面去。 read_html
我遇到的一个问题是它会自动分析里面的数值并将其转成整型、浮点型等,因为网页数据一般不是很规范,这个自动转换很可能不合你的心意。
我遇到这种情况后,分析源码后发现 read_html
这个函数并不能接受额外的参数,而你需要将 dtypes 传递进去,里面有个过程会判断是否有dtypes 传递进来,否则自动试着判断数据类型,主要是数值型。也就是首先你需要定制read_html函数,简单来说就是copy原代码然后加上 **kwargs
传递到 _parse
哪里。然后:
df = read_html(html, dtype=str)
这样就控制所有的数据都是字符串了,参考了 这个网页。
执行某个sql查询语句
使用pd.read_sql 来从某个sql查询语句中获取数据,其有第二个必填参数conn,可以利用sqlalchemy如下获得:
import sqlalchemy
data_source = sqlalchemy.create_engine('sqlite:///mydata.sqlite')
创建DataFrame对象
除了直接从文件读写创建DataFrame对象外,你还可以通过DataFrame类来直接生成DataFrame对象,如下所示:
直接加载python对象
这里支持的python对象有字典,或者已经是DataFrame了。
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
'year': [2000, 2001, 2002, 2001, 2002, 2003],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
frame = pd.DataFrame(data)
当然我们操作DataFrame通常的思路更偏向于一行一行的来,你也可以直接把类似于numpy的ndarray的结构的数据转成DataFrame对象:
pd.DataFrame([[1,2],[2,3]])
再比如:
新建一个随机数填充的DataFrame
新建一个DataFrame对象,随机数填充6行4列,列名分别为 ['a','b','c','d']
。
df = pd.DataFrame(np.random.randn(6,4), columns=['a','b','c','d'])
上面的例子还演示了列名不用默认的0 1 ,而是你直接去指定。
选择合适的时机转入DataFrame
你需要选择一个合适的时机将你的python数据转入DataFrame中,通常这并不是越早越好。DataFrame更快更适合的是那些矩阵操作,或者所有元素都要进行的操作。而对于你的python数据的某个,或者某些的更改操作,并不是某一行,或者某一列的操作,这个时候用DataFrame你会发现很不方便。
DataFrame基础
DataFrame转ndarray
有的时候我们进行计算是希望以ndarray(numpy)的形式来进行的(我们引入DataFrame是因为其有label等等让各个列数据有含义的功能,而到了实际底层算法,可能就是特征1234了,我们不再关心具体特征的名字,这个时候将某部分数据退化为numpy的ndarray数据类型就很必要了,一方面底层算法层不在意这些,第二就是numpy的ndarray对象可以和以前我们常见的那些算法包括新出来的tensorflow很容易对接起来。)
实际转变如下,非常简单:
nd = df.values
参考了 这个网页 。
DataFrame列重命名
在创建DataFrame对象时 columns
参数是设置列名的,DataFrame对象创建之后,你还可以如下所示修改列名。
def set_columns(df, columns):
"""
重新设置列名
"""
df.columns = columns
def rename_column(df, origin_column_name, column_name):
"""
将某个列名更改为某个名字
默认的column 可用 0 1 2 来引用 数值型
"""
d = {}
d[origin_column_name] = column_name
df.rename(columns=d, inplace=True)
def rename_columns(df, columns):
"""
重新设置列名
"""
df.rename(columns = columns, inplace=True)
def rename_column_by_index(df, index, column_name):
"""
不知道列名是多少,只知道是第几列,将其修改为某个名字
"""
df.rename(columns={df.columns[index]: column_name})
DataFrame的append操作
有的时候你需要在现有的Datafrme后面额外添加一行或者几行数据,这个操作很普遍。
import pandas as pd
df = pd.DataFrame(columns=['a','b','c'])
df.append({'a':1}, ignore_index=True)
Out[7]:
a b c
0 1.0 NaN NaN
df.append([{'a':1},{'b':2}], ignore_index=True)
Out[8]:
a b c
0 1.0 NaN NaN
1 NaN 2.0 NaN
如果是上面字典的形式,那么是比如带上 ignore_index=True
参数的。此外还可以append pandas的 Series对象,如果Series对象有name属性,那么这个name将作为插入新的一行的index名字,否则也要带上 ignore_index=True
参数。
索引
按照列名选择
如果你已经定义列名了,那么选择一列按照列名是最直观的了:
df[column_name]
返回的是Series对象,原DataFrame对象的index部分继续保留,也就是原来你的DataFrame的index是有名字的,那么可以继续使用这些索引名字。
这种引用也可以用于添加某一列或者删除某一列:
del df[column_name]
df[column_name] = series
按照列名选择多个列
df[['a','b','c']]
这样得到的将是一个copy!
iloc方法
因为我是比较喜欢矩阵那种几行几列对于某一具体单元格的描述的,所以我很喜欢用 df.iloc[i][j]
这种形式来索引具体某个单元格的数据,就是i行j列,然后注意如果你的column是指定的数字,不是从0开始的,那么引用0就会出现索引异常【如果你的列名不是数字类型那么没有这个问题】。
唯一要注意的是就是和线性代数里面行列式下标有所不同,这里的索引都是从0开始计数的。
按照索引选择多个列
选择多个列【切片式】
df.iloc[:,0:2]
此外还有种写法【列举式】:
df.iloc[:, [0,2]]
对某一特征列进行某个运算
对于DataFrame中的某一特征列,其为Series对象,推荐使用 map
方法:
df['commas'] = df['text'].map(lambda text: text.count(','))
参考了 这个网页 ,apply方法可以作用方向为行或者列,然后apply方法主要针对dataframe对象整体的操作。
搜索语句
DataFrame可以通过如下的搜索语句来对针对某些特征列的值进行判断,从而过滤掉某些行。
df[df['col1']==1]
df[(df['col1']==1)|(df['col2']==1)]
df[(df['col1']==0) & (df['col2']==0)]
按照行排序
df.sort_index(axis=1, ascending=False)
按照列排序
df.sort_values(by='B')
绘图相关
绘制散点图
DataFrame.plot.scatter(x, y, s=None, c=None, **kwds)
根据数据记录 x 列(由x参数指定)和 y 列(由y参数指定)的一一对应的数据,来绘制散点图。