pandas使用指南:初学者向(上)

pandas 使用指南(上)

pandas作为一种可以提供类似于R中dataframe数据结构的module对于经常进行机器学习和数据处理的同学是一种非常高效的数据结构工具。Pandas上面已经提供了一份简易指南,但是全文太长了(虽然其标榜十分钟内可以学会),故而决定写一份旨在给刚刚开始使用pandas的初学者的简化版,因此如果读者已经有一定的pandas使用经验的话,可以略过本文。

本文的主要内容包括:

  • 解释�dataframe的基本结构
  • 几种常见的创建dataframe的方法
  • 几种常用的获得dataframe中数据的方法
  • 几种对已创建的dataframe进行数据修改的方法
  • dataframe中两个常用的函数:groupby以及apply

我们首先导入需要的module:

In [1]: import pandas as pd
In [2]: import numpy as np

基本概念

series

series是pandas中基本的数据结构,它的结构与一个list类似,但是却拥有自己的索引。在实际应用中,dataframe的每一个列对一个series。正因为这些series和dataframe一样都有索引,因此在把一个series加入到dataframe中时,必须考虑他们的索引是否对应。

In [3]: s1 = pd.Series([1,3,5,6,8])

In [4]: s1
Out[4]: 
0    1
1    3
2    5
3    6
4    8
dtype: int64

In [5]: s2 = pd.Series(['a', 'b', 'c'])

In [6]: s2
Out[6]:
0    a
1    b
2    c
dtype: object

dataframe

pandas中的dataframe与R中的dataframe基本类似,可以提供一种类似于表格的数据结构,每一列都是一个series,这些series拥有与整个dataframe相同的索引。

In [7]: index = range(6)

In [8]: index
Out[8]: [0, 1, 2, 3, 4, 5]

In [9]: df = pd.DataFrame(np.random.randn(6,4), index=index, columns=list('ABCD'))

In [10]: df
Out[10]:
          A         B         C         D
0  0.531734 -1.292527 -0.627073 -1.900115
1 -0.715616  2.007529 -0.535181 -0.055376
2 -0.051779  0.751669 -1.150100  1.295839
3 -1.749876  0.962153  0.489654 -0.134320
4 -0.350185 -0.495535  0.116741  1.192340
5  0.844690 -0.111987 -1.221936 -0.714337

索引

索引在dataframe和series中都有应用,简单来看,它是一种类似于整数array的数据结构。


In [11]: df.index
Out[11]: Int64Index([0, 1, 2, 3, 4, 5], dtype='int64')

In [12]: type(df.index)
Out[12]: pandas.indexes.numeric.Int64Index

但是需要注意的是,并不是每一个dataframe和series的索引都一定是从0开始,在数据的操作过程中,索引有时候会发生变化。


In [13]: df2 = df[3:5]

In [14]: df2
Out[14]:
          A         B         C        D
3 -1.749876  0.962153  0.489654 -0.13432
4 -0.350185 -0.495535  0.116741  1.19234

In [15]: df2.index
Out[15]: Int64Index([3, 4], dtype='int64')

创建dataframe

pandas中的dataframe有很多不同的创建方式,比如可以手动一个一个创建,也可以通过读取文件或者数据库直接生成,以下将一一给予简单介绍。

手动创建

如果没有已经生成的文件或者数据库的数据表,我们可能需要手动创建一个dataframe,并在程序运行过程中不断赋值等等。手动创建的基本命令就是pd.DataFrame(self, data=None, index=None, columns=None, dtype=None, copy=False)

其参数包括dataindexcolumnsdtypecopy,这里我将介绍前三个变量:

  • data: 将要存入dataframe的数据,可以是numpy里面的matrix,也可以是一个简单的2d list。
  • index: 一个可以作为dataframe索引的数列,注意,pandas不会检查是否有重复元素,因此请在作为索引使用前自行检查,以免导致错误
  • columns: 一个string的list,每一个元素代表一个列的名字,顺序与列的顺序相同

In [16]: index = [1, 1, 2, 3, 4]

In [17]: index
Out[17]: [1, 1, 2, 3, 4]

In [18]: data = [range(4), range(1, 5), range(2, 6), range(3, 7), range(4, 8)]

In [19]: data
Out[19]: [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]

In [20]: df2 = pd.DataFrame(data=data, index=index, columns=list('ABCD'))

In [21]: df2
Out[21]:
   A  B  C  D
1  0  1  2  3
1  1  2  3  4
2  2  3  4  5
3  3  4  5  6
4  4  5  6  7

从文件中读取

以csv文件为例,使用read_csv函数即可。假设路径内有一个文件名为weather.csv,其主要内容如下:

,date,rain,snow,weather
0,20160101,0,0,0
1,20160102,0,0,0
2,20160103,0,0,0
3,20160104,0,0,0
4,20160105,0,0,0
5,20160106,0,0,0
6,20160107,0,0,0
7,20160108,0,0,0
8,20160109,1,0,1
9,20160110,1,0,1
10,20160111,0,0,0

其读取过程如下:


In [22]: df2 = pd.read_csv('weather.csv')

In [23]: df2
Out[23]:
    Unnamed: 0      date  rain  snow  weather
0            0  20160101     0     0        0
1            1  20160102     0     0        0
2            2  20160103     0     0        0
3            3  20160104     0     0        0
4            4  20160105     0     0        0
5            5  20160106     0     0        0
6            6  20160107     0     0        0
7            7  20160108     0     0        0
8            8  20160109     1     0        1
9            9  20160110     1     0        1
10          10  20160111     0     0        0

这里,第一列在csv中没有标题,所以读取后在dataframe里面的列名称就叫Unnamed: 0

从sql中读取

如果要从sql中读取,我们需要了解一点sql的基本知识,同时在python中安装sqlalchemy,然后使用read_sql函数。
现假设我们的database中有一个数据表的名字就叫做weather,其内容与csv文件基本一样,那么示例如下(我们使用postgresql为例,但是mysql等等基本相同):


In [24]: from sqlalchemy import create_engine

In [25]: database_engine = create_engine('postgresql://[用户名]:[对应密码]@localhost:5432/[database名]', echo=False)

In [26]: weather_df = pd.read_sql("SELECT * FROM weather", con=database_engine)

In [27]: weather_df
Out[27]:
    id      date  rain  snow  weather
0    0  20160101     0     0        0
1    1  20160102     0     0        0
2    2  20160103     0     0        0
3    3  20160104     0     0        0
4    4  20160105     0     0        0
5    5  20160106     0     0        0
6    6  20160107     0     0        0
7    7  20160108     0     0        0
8    8  20160109     1     0        1
9    9  20160110     1     0        1
10  10  20160111     0     0        0

使用dataframe

dataframe的使用主要在于根据使用者的需要查看并获取里面的数据。

查看数据

dataframe的查看主要包括了解整个数据表的基本信息,了解里面的数据大致特征,并查看某特定几行的数据。下面笔者将一一进行介绍。

查看数据表的基本信息

使用info函数。


In [28]: weather_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 11 entries, 0 to 10
Data columns (total 5 columns):
id         11 non-null int64
date       11 non-null int64
rain       11 non-null int64
snow       11 non-null int64
weather    11 non-null int64
dtypes: int64(5)
memory usage: 512.0 bytes

查看开头或尾部的数据表

查看开头:使用head函数
查看尾部:使用tail函数


In [30]: weather_df.head(5)
Out[30]:
   id      date  rain  snow  weather
0   0  20160101     0     0        0
1   1  20160102     0     0        0
2   2  20160103     0     0        0
3   3  20160104     0     0        0
4   4  20160105     0     0        0

In [31]: weather_df.tail(5)
Out[31]:
    id      date  rain  snow  weather
6    6  20160107     0     0        0
7    7  20160108     0     0        0
8    8  20160109     1     0        1
9    9  20160110     1     0        1
10  10  20160111     0     0        0

获取数据

此处为了提高程序效率,推荐使用一下四个行数来获取数据: iloclociatat

获取行或列

获取多行

In [32]: weather_df[3:8]
Out[32]:
   id      date  rain  snow  weather
3   3  20160104     0     0        0
4   4  20160105     0     0        0
5   5  20160106     0     0        0
6   6  20160107     0     0        0
7   7  20160108     0     0        0

获取单行

使用iloc或者loc


In [33]: weather_df.iloc[3]
Out[33]:
id                3
date       20160104
rain              0
snow              0
weather           0
Name: 3, dtype: int64

In [34]: weather_df.loc[3]
Out[34]:
id                3
date       20160104
rain              0
snow              0
weather           0
Name: 3, dtype: int64

此处的ilocloc结果相同,但并不代表两者意义一样。loc通过索引获得对应行,iloc通过行号来获得对应行。例如(注意索引)


In [35]: df = weather_df[3:8]

In [36]: df
Out[36]:
   id      date  rain  snow  weather
3   3  20160104     0     0        0
4   4  20160105     0     0        0
5   5  20160106     0     0        0
6   6  20160107     0     0        0
7   7  20160108     0     0        0

In [37]: df.iloc[3]
Out[37]:
id                6
date       20160107
rain              0
snow              0
weather           0
Name: 6, dtype: int64

In [38]: df.loc[3]
Out[38]:
id                3
date       20160104
rain              0
snow              0
weather           0
Name: 3, dtype: int64

获取单列

有两种方式


In [39]: df.date
Out[39]:
3    20160104
4    20160105
5    20160106
6    20160107
7    20160108
Name: date, dtype: int64

In [40]: df['date']
Out[40]:
3    20160104
4    20160105
5    20160106
6    20160107
7    20160108
Name: date, dtype: int64

获取多列

使用loc函数或iloc函数


In [41]: df.loc[:, ['date', 'snow']]
Out[41]:
       date  snow
3  20160104     0
4  20160105     0
5  20160106     0
6  20160107     0
7  20160108     0

In [42]: df.iloc[:, :2]
Out[42]:
   id      date
3   3  20160104
4   4  20160105
5   5  20160106
6   6  20160107
7   7  20160108

两者的不同在于,loc是使用索引和列名称来获得所需的列,iloc是使用行号和列号来获取所需的列。

获取某个数据

要获取某一个数值,iloclociatat都可以实现。


In [43]: df.iloc[3, 1]
Out[43]: 20160107

In [44]: df.iat[3, 1]
Out[44]: 20160107

In [45]: df.loc[3, 'date']
Out[45]: 20160104

In [46]: df.at[3, 'date']
Out[46]: 20160104

从该例子可以看出,ilociat都是通过行数和列数来获取特定的单个元素,而locat都是通过索引和列名称来获取特定的单个元素。

利用bool下标来获取数据

有些时候,我们只希望通过一些判断或者比较获得一部分数据,例如,在weather_df中,我希望获得以下几组数据:

  • 获取日期在20160106到20160110(包括首尾)之间的所有行
  • 获取名称为weather的列中值为1的所有行
  • 获取日期在[20160106, 20160104, 20160108]这个list中的所有行
  • 以上三组数据中,每组我只想获得id, date和weather这三列

示例将按顺序完成以上几项:


In [47]: weather_df[(weather_df['date'] >= 20160106) & (weather_df['date'] <= 20160110)]
Out[47]:
   id      date  rain  snow  weather
5   5  20160106     0     0        0
6   6  20160107     0     0        0
7   7  20160108     0     0        0
8   8  20160109     1     0        1
9   9  20160110     1     0        1

In [48]: weather_df[weather_df['weather'] == 1]
Out[48]:
   id      date  rain  snow  weather
8   8  20160109     1     0        1
9   9  20160110     1     0        1

In [49]: weather_df[weather_df.date.isin([20160106, 20160104, 20160108])]
Out[49]:
   id      date  rain  snow  weather
3   3  20160104     0     0        0
5   5  20160106     0     0        0
7   7  20160108     0     0        0

In [50]: weather_df[(weather_df['date'] >= 20160106) & (weather_df['date'] <= 20160110)].loc[:, ['id', 'date', 'weather']]
Out[50]:
   id      date  weather
5   5  20160106        0
6   6  20160107        0
7   7  20160108        0
8   8  20160109        1
9   9  20160110        1

In [51]: weather_df[weather_df['weather'] == 1].loc[:, ['id', 'date', 'weather']]
Out[51]:
   id      date  weather
8   8  20160109        1
9   9  20160110        1

In [52]: weather_df[weather_df.date.isin([20160106, 20160104, 20160108])].loc[:, ['id', 'date', 'weather']]
Out[52]:
   id      date  weather
3   3  20160104        0
5   5  20160106        0
7   7  20160108        0

通过上述几个例子,我们可以发现通过条件判断来获取部分数据的基本格式就是类似于dataframe[dataframe.column > value] 或者dataframe[dataframe.column.isin(list)]

那么其原理呢?

事实上他们先根据方括号内的条件判断生成了一个由bool值构成的series: (weather_df['date'] >= 20160106) & (weather_df['date'] <= 20160110), weather_df['weather'] == 1或者weather_df.date.isin([20160106, 20160104, 20160108])
然后在根据这个新的series来选取bool值为true的行。


In [53]: weather_df
Out[53]:
    id      date  rain  snow  weather
0    0  20160101     0     0        0
1    1  20160102     0     0        0
2    2  20160103     0     0        0
3    3  20160104     0     0        0
4    4  20160105     0     0        0
5    5  20160106     0     0        0
6    6  20160107     0     0        0
7    7  20160108     0     0        0
8    8  20160109     1     0        1
9    9  20160110     1     0        1
10  10  20160111     0     0        0

In [54]: weather_df.date.isin([20160106, 20160104, 20160108])
Out[54]:
0     False
1     False
2     False
3      True
4     False
5      True
6     False
7      True
8     False
9     False
10    False
Name: date, dtype: bool

In [55]: weather_df[weather_df.date.isin([20160106, 20160104, 20160108])]
Out[55]:
   id      date  rain  snow  weather
3   3  20160104     0     0        0
5   5  20160106     0     0        0
7   7  20160108     0     0        0

常用到的判断主要包括数值的大小以及元素是否在给定的list或者set中,前者用>, >=, <, 或者<=,后者用.isin。多个逻辑判断的连接使用&或者|
当然也存在更加复杂的逻辑判断,比如判定某一个dataframe中某一个string构成的列的每一个元素的第三到第六个构成的substring必须在某个给定区间,我的常用方法是使用apply函数,这部分内容将在后面给出解释和示例。

剩下的在后半部继续写吧。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容