上一期我们了解了Pandas里面Series数据结构,了解了如何创建修改,清理Series,也了解了一些统计函数,例如方差,标准差,峰度这些数学概念。那么今天我们就来了解Pandas里面的另一个数据结构-----DataFrame。
DataFrame拆开的英文意思是数据框架。事实上它就是一个数据框架,一个类似于数据库中表一样的结构。
比如说我们现在有这样一张表,那么把这张表做成dataframe,先把每一列都提取出来,然后将这些在列的数据都放到一个大的集合里,在这里我们使用字典。(这里我们取姓名,年龄和收入这些字段)
import pandas as pd data = {'Fname': ['amy', 'john', 'tony'], 'age': [50, 55, 54], 'income': [1000000, 500000, 400000000]} df1 = pd.DataFrame(data) print(df1)
这个时候我们看到这些数据做成的dataframe真的就像一个表一样,事实上它真的就是一张表。
我们把每一列数据都取出来,做成一个list(其实就是我们上期说的Series)。
如果我们想为这些数据添修改索引列(就是数据中的0,1,2),可以使用index参数指定索引。
df2 = pd.DataFrame(data, index=['A', 'B', 'C'], columns=['Fname', 'age', 'income']) print(df2)
所以如果构造一个DataFrame,那就需要想好有哪几个列,把列对应的数据做成一个列表放进去。就可以了。说白了就是每个列都是一个Series,DataFrame = n * Series
下面我们来看看一些基础的称呼:
在pandas里面有一些基础的属性需要搞明白,这就和数据库差不多。我们对照数据来理解一下。dataframe里面有个属性叫index,那这个就是索引对应的也是数据库的索引,你也可以把它理解成主键。第二个属性是columns,这个就是一列。对应数据库的表也是一列。有多少个columns就有多少列了~第三个属性是rows,rows大家可以对比成数据的记录,有多少条记录就有多少rows。
当然,我们创建dateframe 的时候用的数据可能不是字典,可能就像是多个Series,想直接把它拼成dataframe,这样可以吗?
答案是可以的。我们可以直接使用多个Series去做出一个dataframe。
import pandas as pd import numpy as np s1 = np.array([1, 2, 3, 4]) s2 = np.array([5, 6, 7, 8]) df = pd.DataFrame([s1, s2]) print(df)
这就是我们上节课讲的,Series有默认索引,从零开始,那这个dataframe也就会和Series一样,如果不给他指定值(列名或索引),他就会从零开始计数。
我们工作中除了手动创建DataFrame,绝大多数数据都是读取文件获得的,例如读取csv文件,excel文件等等,那下面我们来看看pandas如何读取文件呢?
pd.read_csv(filename):从CSV文件导入数据 pd.read_table(filename):从限定分隔符的文本文件导入数据 pd.read_excel(filename):从Excel文件导入数据 pd.read_sql(query, connection_object):从SQL表/库导入数据 pd.read_json(json_string):从JSON格式的字符串导入数据 pd.read_html(url):解析URL、字符串或者HTML文件,抽取其中的tables表格 pd.read_clipboard():从你的粘贴板获取内容,并传给read_table() pd.DataFrame(dict):从字典对象导入数据,Key是列名,Value是数据
pandas支持从多个数据源导入数据,包含文件,字典,json,sql,html等等。
那我们先来看看文件的导入:
我们创建一个csv文件,填写以上数据。
下面我们读取这个文件:
import pandas as pd df = pd.read_csv("ex.csv") print(df)
读出来的数据就是一个dataframe,可以直接对他进行操作。
如果想获取前几行值可以直接使用head方法,或者切片,都是可以拿到前两行的值的。读取数据的方法提供如下几种:
df.head(n):查看DataFrame对象的前n行 df.tail(n):查看DataFrame对象的最后n行 df.shape():查看行数和列数 df.info():查看索引、数据类型和内存信息 df.describe():查看数值列的汇总统计 s.value_counts(dropna=False):查看Series对象的唯一值和计数 df.apply(pd.Series.value_counts):查看DataFrame对象中每一列的唯一值和计数
print(df.head(2)) print(df[0:2])
读取excel:
import pandas as pd score = pd.DataFrame(pd.read_excel('data.xlsx')) score.to_excel('data1.xlsx') print(score)
读取文件的示例就到这里,基本上每种文件都是一样的。
关于DataFrame里面还有一些修改表结构的操作,可以来适当了解一下:
import pandas as pd import numpy as np val = np.arange(10, 60).reshape(10, 5) col = ["ax", "bx", "cx", "dx", "ex"] idx = list("abcdefghij") df1 = pd.DataFrame(val, columns = col, index = idx) print(df1) print("*" * 21, "<- dataframe") df2 = df1.rename(columns={"ax": "修改1", "bx": "修改2"}) print(df2) print("*" * 21, "<- dataframe")
通过rename方法来修改列名,本质上并没有修改原来的dataframe,而是生成新的dataframe替换了列名。
在DataFrame中增加一列,我们可以直接给值来增加一列,就和python的字典里面添加元素是一样的:
import pandas as pd import numpy as np val = np.arange(10, 60).reshape(10, 5) col = ["ax", "bx", "cx", "dx", "ex"] idx = list("abcdefghij") df1 = pd.DataFrame(val, columns=col, index=idx) print(df1) nval = val = np.arange(100, 110).reshape(10, 1) df1["fx"] = nval print(df1)
连接多个dataframe,这个就和数据库一样,可以联想一下数据库之间的表连接,在dataframe里面我们使用contact方法。我们做的连接是全连接,如果数据不全的就会拿NaN来补:
import pandas as pd import numpy as np val1 = np.arange(10, 40).reshape(10, 3) val2 = np.arange(50, 80).reshape(10, 3) col1 = ["ax", "bx", "cx"] col2 = ["cx", "dx", "ex"] idx = list("abcdefghij") df1 = pd.DataFrame(val1, columns=col1, index=idx) df2 = pd.DataFrame(val2, columns=col2, index=idx) print(df1) print(df2) df3 = pd.concat([df1, df2[5:], df1[:5], df2], axis=1) print(df3)
如果不想做全连接,想做一些其他的连接,那我们在连接的时候可以使用merge方法,这样就可以进行不同的连接了。
import pandas as pd df1 = pd.DataFrame({'name':['amy', 'john', 'a', 'b', 'c'], 'data1': range(5)}) df2 = pd.DataFrame({'name':['amy', 'john', 'A', 'B', 'C'], 'data2': range(5)}) # 指定 name 这列进行连接。 df3 = pd.merge(df1, df2, on='name') # 内连接 df3 = pd.merge(df1, df2, how='inner') # 左连接 df3 = pd.merge(df1, df2, how='left') # 右连接 df3 = pd.merge(df1, df2, how='right')
在这后,我们需要做的就是处理数据了。把给定的一些数据处理好,这就看我们这些人是如何处理数据了。俗话说的好,条条大路通罗马。每个数据分析师都有自己处理数据的手段,最好能达到目的就可以了。
我们一开始拿到的原始数据多多少少是有些问题的,可能会丢失数据啊,有脏数据啊等等,这个时候需要我们来对数据进行一些清理。数据清洗是在数据准备的过程中必不可少的环节,pandas为我们提供了一系列清洗数据的方法。这里我们就来介绍一些。
首先我们可能需要从给定的数据中提取出一些我们想要的数据,而Pandas 提供了一些选择的方法,这些选择的方法可以把数据切片,也可以把数据切块。下面我们简单介绍一下:
选择一列:
data['column_name']
选择一列的前几行数据:
data['columns_name'][:n]
选择多列:
data[['column1','column2']]
Where 条件过滤:
data[data['column_name'] > condition]
那我们可以考虑一下产生这些异常数据的原因有哪些呢?
一般的,产生这个问题可能的原因可能有以下几点:
1、从来没有填正确过
2、数据不可用
3、计算错误
对于这些问题,我们处理这些异常数据无非就是下面几种办法:
1、为缺失数据赋值默认值
2、去掉/删除缺失数据行
3、去掉/删除缺失率高的列
添加默认值(fillna)
现在我们的数据中,年龄出现了异常值None,这个时候我们需要把None替换成标准的年龄值,我们假设研究对象的年龄平均在23左右,就把默认值设成23,那我们就可以成功的把None替换成23了。
import pandas as pd data = {'Fname': ['amy', 'john', 'tony'], 'age': [50, None, 54], 'income': [1000000, 500000, 400000000]} df1 = pd.DataFrame(data) df1.age = df1.age.fillna(23) print(df1)
删除不完整的行(dropna)
假设我们想删除任何有缺失值的行。这种操作具有侵略性,但是我们可以根据我们的需要进行扩展。
我们可以使用isnull来查看dataframe中是否有缺失值。
df1.isnull().values.any()
删除任何包含 NA 值的行是很容的:
df1.dropna()
当然,我们也可以删除一整行的值都为 NA:
df1.dropna(how='all')
我们也可以增加一些限制,在一行中有多少非空值的数据是可以保留下来的(在下面的例子中,行数据中至少要有 5 个非空值)
df1.drop(thresh=5)
删除不完整的列(dropna)
我们可以上面的操作应用到列上。我们仅仅需要在代码上使用 axis=1 参数。这个意思就是操作列而不是行。(默认是axis=0。)
删除一整列为 NA 的列:
data.drop(axis=1, how='all')
删除任何包含空值的列:
data.drop(axis=1. how='any')
规范化数据类型
我们可以在读取文件的时候就限定,哪一列的数据是什么类型。
data = pd.read_csv('../data/moive.csv', dtype={'duration': int}) data = pd.read_csv('./data/moive.csv', dtype={'year':str})
还有一些注意点就是,当数据变成人为的破环,例如大写变小写,单词拼错等。使用一些方法来修复,具体是用正则还是其他方法,就看你了。
删除重复值(drop_duplicates)
表中难免会有一些重复的记录,这时候我们需要把这些重复的数据都删除掉。
import pandas as pd data = {'Fname': ['amy', 'amy', 'john', 'tony'], 'age': [50, 50, None, 54], 'income': [1000000, 1000000, None, 400000000]} df1 = pd.DataFrame(data) print(df1.duplicated()) print(df1.drop_duplicates())
使用duplicated方法可以查找出是否有重复的行,使用drop_duplicated方法就可以直接将重复的行删除了。
关于dataframe中的统计函数,这里就不多说什么了,具体已经在Serires那个章节中列详细出来了。具体可以参考以下方法。
df.count()#非空元素计算 df.min()#最小值 df.max()#最大值 df.idxmin()#最小值的位置,类似于R中的which.min函数 df.idxmax()#最大值的位置,类似于R中的which.max函数 df.quantile(0.1)#10%分位数 df.sum()#求和 df.mean()#均值 df.median()#中位数 df.mode()#众数 df.var()#方差 df.std()#标准差 df.mad()#平均绝对 偏差df.skew()#偏度 df.kurt()#峰度 df.describe()#一次性输出多个描述性统计指标
下面我们说一下Pandas里面最神奇万能的apply函数。
apply函数可以对DataFrame对象进行操作,既可以作用于一行或者一列的元素,也可以作用于单个元素。apply最神奇的地方就是它里面可以调用函数,我们经常在apply里面写一些功能的匿名函数。
import pandas as pd import numpy as np s = pd.Series(np.arange(2, 6)) print(s) print(s.apply(lambda x: 2 * x))
从上面例子的结果中我们看出数据里面的所有数字都被乘上了2,这就因为我们的apply函数里面写了一个匿名函数,将原来的数据变成两倍(如果你对lambda不懂,可以参考之前文章,介绍python里面的高级函数的)
apply不仅可以适用于整个dataframe,也可以作用于行和列,如果想作用于行,可以添加参数axis=0,如果想作用于列,axis=1。
关于Pandas,我们到这里就算讲完了。欢迎大家前来交流和指点。