BeginMan blog

Pandas入门指南

接触pandas有一段时间了,学习的比较零碎,下面这篇博客是零碎的拼接,源自我看过的一些博文和书籍,绘制一个入门指南。

目录结构:

  1. 数据生成
  2. 数据检查
  3. 数据选取
  4. 数据清洗,预处理
  5. 数据筛选
  6. 数据汇总与分析
  7. 数据图表与输出

一.数据生成

可以生成数据的方案很多:

  • dict/list
  • 任何数据库(做下简单转换即可)
  • web/URL
  • csv/excel
  • 等…

# mysql result to pandas
def to_pandas(rs):
    res = rs.fetchall()
    if not res:
        return
    
    df = DataFrame(res)
    df.columns = rs.keys()
    return df
    
# mongodb to pandas

def parse_data(cursor):
    df =  pd.DataFrame(list(cursor))
    return df
    
# redis get/set pandas
# set
redisConn.set("key", df.to_msgpack(compress='zlib'))
# get
pd.read_msgpack(redisConn.get("key"))

下面以这个例子展开:

df = pd.DataFrame({"id":[1001,1002,1003,1004,1005,1006], 
                   "date":pd.date_range('20130102', periods=6),
                   "city":['Beijing ', 'SH', ' guangzhou ', 'Shenzhen', 'shanghai', 'BEIJING '],
                   "age":[23,44,54,32,34,32],
                   "category":['100-A','100-B','110-A','110-C','210-A','130-F'],
                   "price":[1200,np.nan,2133,5433,np.nan,4432]},
                   columns =['id','date','city','category','age','price'])

二.数据检查

  • 数据维度
  • 数据表信息
  • 数据格式
  • 查看空值
  • 查看唯一值
  • 查看数据表数值
  • 查看列名称
  • 取样

shape属性查看维度:

df.shape
(6, 6)

info()方法查看整个数据表信息如维度,大小,列名,格式等

In [4]: df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6 entries, 0 to 5
Data columns (total 6 columns):
id          6 non-null int64
date        6 non-null datetime64[ns]
city        6 non-null object
category    6 non-null object
age         6 non-null int64
price       4 non-null float64
dtypes: datetime64[ns](1), float64(1), int64(2), object(2)
memory usage: 368.0+ bytes

df.dtypes 查看数据表格式

isnull() 查看空值(true,false表示)

df.isnull()
df['price'].isnull()

unique() 查看指定列的唯一值:

In [12]: df.city.unique()
Out[12]: array(['Beijing ', 'SH', ' guangzhou ', 'Shenzhen', 'shanghai', 'BEIJING '], dtype=object)

In [13]: df['city'].unique()
Out[13]: array(['Beijing ', 'SH', ' guangzhou ', 'Shenzhen', 'shanghai', 'BEIJING '], dtype=object)

df.values查看数据表的值

df.columns查看列

In [16]: df.columns
Out[16]: Index(['id', 'date', 'city', 'category', 'age', 'price'], dtype='object')

三.数据选取

涉及方法:

  • iloc: 通过行号选取
  • loc:通过label或者条件语句选取
  • ix:组合选取

下面通过这个csv文件作为数据源

import pandas as pd
import random
data = pd.read_csv('https://s3-eu-west-1.amazonaws.com/shanebucket/downloads/uk-500.csv')

# 生成id字段
data['id'] = [random.randint(0, 1000) for i in range(data.shape[0])]
data.head(10)

3.1 iloc

“iloc” in pandas is used to select rows and columns by number, data.shape[0] as row number total, data.shape[1] as column number total.

[x,y] goes from x to y-1

# 行查询
data.iloc[-1] # 选择最后一行。

# 列查询
data.iloc[:,列的索引]  # 查看指定列
data.iloc[:,0]      # 第一列的所有数据 (first_name)

# 多行多列查询
data.iloc[0:5]  # 0~5行
data.iloc[:, 0:2] # 0~2列 (first_name, last_name)
data.iloc[0:5, 0:2] # 前5行的前两列 (first_name, last_name)
data.iloc[[0,3,6], [0,1]]  # 第1,4,7行中第1,2列(first_name, last_name)

注意:当只有一行选择时返回的是Series类型:

3.2 loc

loc有如下两个用例:

  1. 通过label/index 选择行
  2. 通过 boolean / conditional lookup 选择行

3.2.1 Label-based / Index-based indexing using .loc

对于第一种 Label-based / Index-based ,通过df.set_index() 设置索引,.loc方法直接基于索引值来选取,如下设置last_name 为索引:

接下来就可以基于index选择了。

可以选择多个:data.loc[['Andrade', 'Veness']]

提供列名的话可选择指定的列,如下:

也可以使用:切片选择一组,都是开区间,如下:

我们改变下index基于id列作为索引:

data.set_index('id', inplace=True)
# select the row with 'id' = 487
data.loc[487]

要注意的是:

data.loc[487] (the row with index value 487) is not equal to data.iloc[487] (the 487th row in the data).

3.2.2 Boolean / Logical indexing using .loc

通过data.loc[<selection>] 设置带有布尔数组的条件选择来选取数据,同样拿上面以last_name作为索引的数据为例,查找first_name为Evan的数据:

原理就是selection 如:data['first_name'] == 'Evan' 返回包含所有index对应的True,False的Series对象,然后loc基于True的位置找到对应的一行数据。

同样,第二个参数用于选取指定的列:

注意,当选取一个列时返回Series,用[]包起来则是DataFrame

其他实例:

# Select rows where the email column ends with 'hotmail.com', include all columns
data.loc[data['email'].str.endswith("hotmail.com")]  

# Select rows with last_name equal to some values, all columns
data.loc[data['first_name'].isin(['France', 'Tyisha', 'Eric'])]    

# Select rows with first name Antonio AND hotmail email addresses
data.loc[data['email'].str.endswith("gmail.com") & (data['first_name'] == 'Antonio')] 

# select rows with id column between 100 and 200, and just return 'postal' and 'web' columns
data.loc[(data['id'] > 100) & (data['id'] <= 200), ['postal', 'web']] 

# A lambda function that yields True/False values can also be used.
# Select rows where the company name has 4 words in it.
data.loc[data['company_name'].apply(lambda x: len(x.split(' ')) == 4)] 

# Selections can be achieved outside of the main .loc for clarity:
# Form a separate variable with your selections:
idx = data['company_name'].apply(lambda x: len(x.split(' ')) == 4)
# Select only the True values in 'idx' and only the 3 columns specified:
data.loc[idx, ['email', 'first_name', 'company']]

3.2.3 通过loc更改数据

当然我们也可以更改多个

3.3 ix

ix是iloc和loc的混合版本,在pandas 0.20.1版本后被废弃,所以我们优先使用iloc和loc,通常ix扮演loc的角色,但是整数类型选择的iloc, 条件就是df的索引不能是整数的。

可以看出来它的表示并不是很清晰,最好不要用以避免歧义。

四.数据清洗,预处理

常见的有:

  • 删除或填充空值
  • 清理操作
  • 更改数据格式
  • 更改列名称
  • 删除重复值
  • 数值修改及替换
  • df合并
  • 排序
  • 分组
  • 分列

数据源:

df = pd.DataFrame({"id":[1001,1002,1003,1004,1005,1006], 
                   "date":pd.date_range('20130102', periods=6),
                   "city":['Beijing ', 'SH', ' guangzhou ', 'Shenzhen', 'shanghai', 'BEIJING '],
                   "age":[23,44,54,32,34,32],
                   "category":['100-A','100-B','110-A','110-C','210-A','130-F'],
                   "price":[1200,np.nan,2133,5433,np.nan,4432]},
                   columns =['id','date','city','category','age','price'])

4.1 删除或填充空值

删除涉及 dropna, 填充是fillna

dropna 语法如下:

df.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)

"""
Parameters
----------
axis : {0 or 'index', 1 or 'columns'}, or tuple/list thereof
    Pass tuple or list to drop on multiple axes
how : {'any', 'all'}
    * any : if any NA values are present, drop that label
    * all : if all values are NA, drop that label
"""

fillna的语法比较丰富,看文档就行了。这里把NaN填充为0, df.fillna(0)

4.2 清理操作

mapapply 操作,如删除空格。

df['city'] = df['city'].map(str.strip)

大小写转换:

4.3 更改数据格式

astype来处理,如将price改成int型:

df['price'].astype('int')

4.4 更改列名称

rename函数,如:

df.rename(columns={'category': 'category-size'})

4.5 删除重复值

drop_duplicates函数,如果设置keep=’last‘参数,那么第一个被匹配到的重复值被删除,否则最后一个被删除。

4.6 数值修改及替换

replace函数

df['city'].replace('sh', 'shanghai')

4.7 df合并

mergeconcat 函数用于df合并, 我们常见的一种方式是查询大量mysql数据,然后合并在一块,如下示例:

sql = "SELECT * FROM users limit 100000"
dfs = []
for chunk in pd.read_sql_query(sql , engine, chunksize=5000):
    dfs.append(chunk)

df = pd.concat(dfs)

concat适合合并多个df,以append形式合并。merge有点SQL-Like, 如join, left join, right join等操作。下面以df1作为合并的数据源:

df1=pd.DataFrame({"id":[1001,1002,1003,1004,1005,1006,1007,1008], 
                  "gender":['male','female','male','female','male','female','male','female'],
                  "pay":['Y','N','Y','Y','N','Y','N','Y',],
                  "m-point":[10,12,20,40,40,40,30,20]})

4.8 排序

4.9 数据分组

where 函数,对数据进行判断和分组, 将符合条件的分为一组,不符合条件的分为另一组

where(条件, 值1,值2) 有点三元运算符的感觉。

还可以对多个字段的值进行判断后对数据进行分组, 如:

df_inner['group'] = np.where((df_inner['price'] > 3000) & (df_inner['city'] == 'Shenzhen'), 'high', 'low')

多条件用 ()括每个条件 然后 &, | 连接.

处理where之外,还可以用loc直接修改

5.0 数据分列

五.数据筛选

与或非(&,|,!), 如 df.loc[筛选条件], 对于多个条件则需要用()分别括起来。

六.数据汇总与分析

主要用到:

  • merge
  • group

6.1 合并

数据源:

user_usage = pd.read_csv('https://raw.githubusercontent.com/shanealynn/Pandas-Merge-Tutorial/master/user_usage.csv')
user_usage.head(5)

user_device = pd.read_csv('https://raw.githubusercontent.com/shanealynn/Pandas-Merge-Tutorial/master/user_device.csv')
user_device.head(5)

android_devices = pd.read_csv('https://raw.githubusercontent.com/shanealynn/Pandas-Merge-Tutorial/master/android_devices.csv')
android_devices.head(5)

先对use_id作为key进行merge:

# merge user_usage and user_device and add the “device” and “platform” columns to user_usage
result = pd.merge(user_usage,
         user_device[['use_id', 'platform', 'device']],
         on='use_id')
result.head()

# user_usage as left
# user_device[['use_id', 'platform', 'device']] as right
# use_id as join key

来试一试 left join吧。

果不其然,再试下outer join

从上述三个例子可以看到 merge操作与SQL join操作基本一样的:

  • merge: inner -> sql: inner join
  • merge: right -> sql: right join
  • merge: left -> sql: left join
  • merge: outer -> sql: full outer join

还可以指定right_on和left_on 来merge:

6.2 数据分析

  • groupby()
  • agg()

八.数据图表与输出

  • to excel
  • to csv
  • ….

比如写入excel:

df_inner.to_Excel('my.xlsx', sheet_name='demo')

参考