5

python笔记:pandas基本使用

 2 years ago
source link: https://gsy00517.github.io/python20200113202851/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
python笔记:pandas基本使用 | 高深远的博客

python笔记:pandas基本使用

发表于 2020-01-13 | 更新于: 2020-02-01 | 分类于 程序与设计 | | 阅读次数:
字数统计: 3.9k字 | 阅读时长 ≈ 14分钟

在python中,Pandas可以说是最实用的库之一,它提供了非常丰富的数据读写方法。可以看一下Pandas中文网提供的Pandas参考文档中对所有I/O函数的总结。

Pandas是一个开源的,BSD许可的库,为python提供高性能、易于使用的数据结构和数据分析工具。它的使用基础是Numpy(提供高性能的矩阵运算);可以用于数据挖掘和数据分析,同时也提供数据清洗的功能。
本文就对Pandas的基本使用做一个简单的归纳,所有代码可以从上往下按顺序依次执行。

References

电子文献:
https://www.cnblogs.com/chenhuabin/p/11477076.html
https://blog.csdn.net/weixin_39791387/article/details/81487549
https://kanoki.org/2019/09/16/dataframe-visualization-with-pandas-plot/
https://pandas.pydata.org/pandas-docs/stable/getting_started/10min.html
https://blog.csdn.net/weixin_41712499/article/details/82719987


这里我想介绍一下一种新的数据格式:csv。它和excel很像,但又不同于excel。csv主要有如下特点:

  1. 纯文本,使用某个字符集,比如ASCII、Unicode、EBCDIC或GB2312(简体中文环境)等;
  2. 由记录组成(典型的是每行一条记录);
  3. 每条记录被分隔符(英语:Delimiter)分隔为字段(英语:Field (computer science))(典型分隔符有逗号、分号或制表符;有时分隔符可以包括可选的空格);
  4. 每条记录都有同样的字段序列。

在Pandas的使用以及AI相关竞赛数据集、结果的存储与使用中,csv文件往往承担着主角的位置。


在具体使用之前,别忘了先导入所需相应的库。

import pandas as pd
import numpy as np

可以使用pd.__version__来输出版本号,注意,这里的“__”是两个“_”,这个很容易搞错且难以发现。


Pandas中文网首页,在介绍完Pandas之后,就重点介绍了一下Pandas的两大利器。分别是DataFrame和Series。这里我先介绍一下Seires,DataFrame在后面有更详细的操作。

  1. Series简介

    Series是一种类似于一维数组的对象,是由一组数据(各种NumPy数据类型)以及一组与之相关的数据标签(即索引)组成。仅由一组数据也可产生简单的Series对象。
    我们可以通过传入一个list的数值来创建一个Series,Pandas会创建一个默认的整数索引:

    s = pd.Series([1, 3, 5, np.nan, 6, 8])

    s
    >>> 0 1.0
    1 3.0
    2 5.0
    3 NaN
    4 6.0
    5 8.0
    dtype: float64

    注:这里用np.nan来产生NaN,但要注意的是np.nan不是一个“空”对象,即使用np.nan == np.nan来判断将返回False,np.nan的类型为基本数据类型float。
    若要对某个值进行空值判断,如对np.nan,需要用np.isnan(np.nan),此时返回为True。

    另外,也可以从字典创建Series。

  2. DataFrame简介

    DataFrame是Pandas中的一个表格型的数据结构,包含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型等),DataFrame即有行索引也有列索引,可以被看做是由Series组成的字典。
    我们可以通过传入一个numpy数组来创建一个DataFrame,如下面带有一个datetime的索引以及被标注的列:

    dates = pd.date_range('20130101', periods = 6)

    dates
    >>> DatetimeIndex(['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04',
    '2013-01-05', '2013-01-06'],
    dtype = 'datetime64[ns]', freq = 'D')

    df1 = pd.DataFrame(np.random.randn(6, 4), index = dates, columns = list('ABCD'))

    df1
    >>> A B C D
    2013-01-01 0.469112 -0.282863 -1.509059 -1.135632
    2013-01-02 1.212112 -0.173215 0.119209 -1.044236
    2013-01-03 -0.861849 -2.104569 -0.494929 1.071804
    2013-01-04 0.721555 -0.706771 -1.039575 0.271860
    2013-01-05 -0.424972 0.567020 0.276232 -1.087401
    2013-01-06 -0.673690 0.113648 -1.478427 0.524988

    注:上面用pd.data_range()生成了一个时间频率freq = 'D'(即天)的日期序列。

    我们也可以通过传入一个可以转换为类Series(series-like)的字典对象来创建一个DataFrame:

    df2 = pd.DataFrame({'A': 1.,
    'B': pd.Timestamp('20130102'),
    'C': pd.Series(1, index = list(range(4)), dtype = 'float32'),
    'D': np.array([3] * 4, dtype = 'int32'),
    'E': pd.Categorical(["test", "train", "test", "train"]),
    'F': 'foo'})

    df2
    >>> A B C D E F
    0 1.0 2013-01-02 1.0 3 test foo
    1 1.0 2013-01-02 1.0 3 train foo
    2 1.0 2013-01-02 1.0 3 test foo
    3 1.0 2013-01-02 1.0 3 train foo

    这里可以使用df2.dtypes来查看不同列的数据类型。

无论是txt文件还是csv文件,在Pandas中都使用read_csv()读取,当然也使用同一个方法写入到文件,那就是to_csv()方法。

df = pd.read_csv(abs_path) #此为绝对路径

为了提供更加多样化、可定制的功能,read_csv()方法定义了数十个参数,还在大部分参数并不常用,以下是几个比较常用的参数:

  1. filepath_or_buffer:文件所在路径,可以是一个描述路径的字符串、pathlib.Path对象、http或ftp的连接,也可以是任何可调用read()的对象。这是唯一一个必传的参数,也就是上面的abs_path。
  2. encoding:编码,字符型,通常为utf-8,如果中文读取不正常,可以将encoding设为gbk。当然,也可以直接将对应文件改成utf-8编码。
  3. header:整数或者由整数组成的列表,用来指定由哪一行或者哪几行作为列名,默认为header = 0,表示用第一列作为列名。若设置header = 0,则指定第二列作为列名。要注意的是,当指定第一行之后的数据作为列名时,前面的所有行都会被略过。也可以传递一个包含多个整数的列表给header,这样每一列就会有多个列名。如果中间某一行没有指定,那么该行会被略过。例如header = [0, 2],则原本的第二行会被省去。而当文件中没有列名一行数据时,可以传递header = None,表示不从文件数据中指定行作为列名,这时Pandas会自动生成从零开始的序列作为列名。
  4. names:接着上面的header,很快就想到是不是可以自己设置列名。names就可以用来生成一个列表,为数据额外指定列名。例如:df = pd.read_csv('abs_path, names=['第一列', '第二列', '第三列', '第四列'])

在数据读取完毕之后,我们可以使用如下代码来快速查看数据是否正确地导入了。

df.head() #看一下导入后df(DataFrame)的前几行,可在括号内输入数字来设定具体显示几行,默认5行
df.tail() #类似,查看后几行

type(df) #查看类型,DataFrame的输出应该是pandas.core.frame.DataFrame



DataFrame

DataFrame的介绍在前面的简介已经写过,这里就不赘述了。事实上,Pandas中的DataFrame的操作,有很大一部分跟numpy中的二维数组的操作是近似的。
在上面的读取处理之后,我们下面对其进行一些简单的操作:

  1. df.head() #上文已提及
    df.tail()

    #查看列名
    print(df.columns)

    #查看索引
    print(df.index)

    #查看各列的数据格式
    print(df.dtypes)

    #查看整个DataFrame的属性信息
    print(df.info())

    #访问对应行
    df.loc[0] #这里访问了第一行,将显示列名和对应每一列第一行的数据
    #具体有关索引请看后文
  2. 在numpy中,我们可以这样判断一个数组中每一个数和对应数值的比较结果:

    a = np.array(range(10))
    a > 3

    输出将是一串布尔型(True、False)的array。
    而在DataFrame中,我们可以用类似的方法通过指定列来进行筛选:

    #筛选第二列中数值大于80
    df[df.第二列 > 80]

    这样就会得到只用符合条件数据的对应行的一个DataFrame。
    我们也可以使用df[(df.第一列 > 80) & (df.第二列 > 80) & (df.第三列 > 80)]来进行多条件的复杂筛选。
    此外,我们可以直接根据列名提取出一个新的表格:

    new = df[['第一列', '第二列']] #new为仅由第一列和第二列组成的一个新的DataFrame
  3. 可以使用如下代码根据单列或者多列的值对数据进行排序:

    df.sort_values(['第二列', '第一列', '第三列'], ascending = [True, True, True])
    #使用df.sort_values(['第二列', '第一列', '第三列']).head()查看排序完后前几行的结果

    这里排序的规则是:根据设置的顺序(这里是先按第二列排),从小到大升序对所有数据进行排序。其中ascending是设置升序(默认True)和降序(False)。若仅选择单列,则无需添加[],这里[]的作用是把选择的行列转换为列表。

  4. 如果觉得我前面取得列名称不好听,可以使用下面这个代码来改成需要的名字:

    df.rename(columns = {'第一列': '好听的第一列', '第二列': '好听的第二列', '第三列': '好听的第三列', '第四列': '好听的第四列',}, inplace = True)

    这里用到了字典。

  5. 前面提到了使用索引来查看第一行,可当没有数字索引,例如我们通过df = pd.DataFrame(scores, index = ['one', 'two', 'three'])把index设为one、two、three时,df.loc[0]就失效了。因此有下面几种处理方法:

    #访问index为“one”的行
    df.loc['one']

    #访问实实在在所谓的第几行(无论index为何)
    df.iloc[0] #注意0指的是第一行

    #ix合并了loc和iloc的功能,当索引为数字索引的时候,ix和loc是等价的
    df.ix[0] #访问第一行
    df.ix['one'] #访问“one”行,这里也指的是第一行
  6. 类似的,DataFrame也支持切片操作,但还是需要注意的。
    这里总结两种切片方式:

    1. 即使用df.loc[:2]ordf.ix[:2]等索引方式,这里这样的话输出为前三行。
    2. 这种方法只能在访问多行数据时使用,例如df[:2]将输出前两行,注意,这里比上面的方法要少一行。此外,值得强调的是,用这种方法访问单行数据是禁止的,例如不能使用df[0]来访问第一行数据。
  7. 上面的索引还有一种用途,就是可以用于插入指定index的新行。

    df.loc['new_index'] = ['one', 'piece', 'is', 'true']
  8. 上面插入的那行中我说了“大秘宝是真实存在的”(海贼迷懂),下面我想把这句话所在的行删了,可以使用df.dtop()来完成。

    df = df.drop('new_index')
  9. 我们可以使用df.第一列.values以array的形式输出指定列的所用值。
    基于此,我们可以使用df.第一列.value_counts()来做简单的统计,也就是对该列中每一个出现数字作频次的统计。
    我们还可以直接对DataFrame做计算,例如:df * n(n为具体数值),结果就是对表中的每一个数值都乘上对应的倍数。

    1. map函数

      map()是python自带的方法, 可以对DataFrame某列内的元素进行操作。
      下面是一种使用实例:

      def func(grade):
      if grade >= 80:
      return "A"
      elif grade >= 70:
      return "B"
      elif grade >= 60:
      return "C"
      else:
      return "D"

      df['评级'] = df.第一列.map(func)

      这样DataFrame后面会自动添加一列名为“评级”,并根据第一列来生成数据填入。

    2. apply函数

      当我们需要进行根据多列生成新的一个列的操作时,就需要用到apply。其用法简单示例如下:

      df['求和'] = df.apply(lambda x: x.第一列 + x.第二列, axis = 1)
    3. applymap函数

      applymap时对dataframe中所有的数据进行操作的一个函数,非常重要。例如,我要让之前所用的score和grade都变成scroe+或者grade+,那么我就可以这样:

      df.applymap(lambda x: str(x) + '+')

      如果是成绩单的话,那么这样操作之后打出来就会好看些啦,哈哈。

  10. 数据可视化本来是一个非常复杂的过程,但Pandas数据帧plot函数的出现,使得创建可视化图形变得很容易。
    这个函数的具体使用可以访问文首给出的第三个参考链接,为一个印度小哥利用kaggle上的数据df.plot()做的一个非常详尽的介绍。
    有机会的话我会结合matplotlib对其做一个搬运与总结,先留个坑。
  11. 我们可以使用df.describe()对数据进行快速统计汇总。输出将包括:count、mean、std、min、25%、50%、75%和max。
    通过df.mean()我们可以按列求均值,如果想要按行求均值,可以使用df.mean(1)
  12. 此外还有使用df.T进行转置,df.dropna(how = 'any')删除所有具有缺失值的数据,df.fillna(value = 5)填充所有缺失数据等高阶用法。详细的可以查阅前面给的参考链接10 minutes to pandas,至于更高阶的,可以看一下cookbook,不过一般还是在运用的过程中遇到需求再查找,一下子记不住那么多的。

通过to_csv()可以将Pandas数据写入到文本文件中,和读取read_csv()类似,它也有几个常用参数:

  1. path_or_buf:表示路径的字符串或者文件句柄,也是必需的。例如:df.to_csv(abs_path)。要注意的是,这里如果abs_path对应的文件不存在,则会新建abs_path的同名文件后再写入,如果本来已存在该文件,则会自动清空该文件后再写入。
  2. sep:分隔符,默认为逗号。当写入txt文件时,就需要这个参数来确定数据之间的分隔符了。
  3. header:元素为字符串的列表或布尔型数据。当为列表时表示重新指定列名,当为布尔型时,表示是否写入列名。这和读取时的使用基本类似。
  4. columns:后接一个列表,用于重新指定写入文件中列的顺序。例如:df.to_csv(abs_path, columns = ['第四列', '第二列', '第三列', '第一列'])
  5. index_label:字符串或布尔型变量,设置索引列列名。原本的索引是空的,使用这个参数就可以给索引添加一个列名。如果觉得不需要添加,同时空着不好看(空的话还是会有分隔符),可以设置为False去掉(同时也将不显示分隔符)。
  6. index:布尔型,是否写入索引列,默认为True。
  7. encoding:写入时所用的编码,默认是utf-8。这个和上述的许多参数其实保持默认即可。

在上面DataFrame一节的最后,我用到了两个匿名函数,这里我想举个例子来简单展示一下匿名函数的使用方法,的确很好用!
当我们对一个数进行操作时,若使用函数,一般会:

def func(number):
return number + 10

这样看上去就有点费代码了,因此有下面的等价匿名函数可以替代:

func = lambda number: number + 10

当然假如想追求代码行数的话也不拦着你~


最近看到了DataWhale的一篇文章,也总结的挺好,在这里推荐一下。


碰到底线咯 后面没有啦

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK