pandas官网

pandas is a Python package providing fast, flexible, and expressive data structures designed to make working with “relational” or “labeled” data both easy and intuitive. It aims to be the fundamental high-level building block for doing practical, real world data analysis in Python. Additionally, it has the broader goal of becoming the most powerful and flexible open source data analysis / manipulation tool available in any language. It is already well on its way toward this goal.

panda 与SQL在很多地方都很相似,具体的对比可以参考该链接

PANDAS的功能

  • 能够很好的处理missing value(NaN)
  • 可以对二维甚至高维的数据对象进行插入和删除
  • 支持将其它python数据结构简单快捷的转变为DataFrame
  • 支持分组计算group by
  • 支出数据重塑与数据透视表
  • 支持智能的基于标签的切片,索引选取等数据操作
  • 支持多个数据集的组合操作:join与merge
  • 支持从多个渠道读取文本数据
  • 支持时间序列time-series操作
  • 支持可视化数据

文件读取

在之前的I/O章节中我们学习了使用open函数来打开文件,read函数来读取数据。但是读取进来的数据都是str的格式,非常不方便我们进行分析。 pandas提供了read_csv函数可以将文件按照固定的格式进行读取,函数能够自动解析数据类型,添加列名与索引等很多功能,能够以结构化的dataframe形式存储数据。

一些注意点:

  1. 尽量避免去读取excel文件,使用通用的csv或者txt格式(excel并不是全平台通用的,它是微软家的)
  2. 注意编码问题,使用encoding参数
  3. 注意处理报错行
  1. import pandas as pd
  2. import numpy as np
  3. print(pandas.__version__) # 查看版本 0.24.2

读文件

  1. # 使用read_csv方式,数据文件和代码文件位于同一目录下
  2. df = pd.read_csv("Restaurant.csv", sep="\t")
  3. # 查看数据文件的头部,默认输出前五行数据
  4. df.head()
  5. # 使用read_excel方式
  6. movie = pd.read_excel("movie.xlsx", sheet_name=0) # 不推荐
  7. df.head()

写文件

  1. # index表示是否要保存索引
  2. df.to_csv("Restaurant_copy.csv", sep="\t", index=False)

DataFrame 与 Series

Series的创建

Series is a one-dimensional labeled array capable of holding any data type (integers, strings, floating point numbers, Python objects, etc.). The axis labels are collectively referred to as the index.

Series是一维的、带标签的、能够存储任意数据类型、的数组

  1. s = pd.Series(data, index=index)

Here, data can be many different things:

  • a Python dict
  • an ndarray (like list)
  • a scalar value (like 5)

The passed index is a list of axis labels. Thus, this separates into a few cases depending on what data is:

  1. # From dict
  2. pd.Series({"name":"jeff", "age":18})
  3. # from array
  4. pd.Series([1,2], index=list("ab"))
  5. # From scala
  6. pd.Series(5, index=list("abcdef"))

DataFrame的创建

DataFrame is a 2-dimensional labeled data structure with columns of potentially different types. You can think of it like a spreadsheet or SQL table, or a dict of Series objects. It is generally the most commonly used pandas object. Like Series, DataFrame accepts many different kinds of input:

DataFrame是二维的、带标签的、不同类型列的、数据结构。你可以看作类似于EXCEL工作簿或者SQL表或者是由Series组成的字典。

DataFrame由一个或者多个Series组成,DataFrame的一行或者一列就是一个Series。

  1. pd.Dataframe(data, index=index, columns=columns)

Here, data can be many different things:

  • Dict of 1D ndarrays, lists, dicts, or Series
  • 2-D numpy.ndarray
  • Structured or record ndarray
  • A Series
  • Another DataFrame

Along with the data, you can optionally pass index (row labels) and columns (column labels) arguments. If you pass an index and / or columns, you are guaranteeing the index and / or columns of the resulting DataFrame.

  1. # 通过字典方式创建
  2. df = pd.DataFrame({"name":["Jeff", "Tom", "Peter"], "age": [24, 25, 20], "height": [180, 165, 179]})
  3. df

执行

name age height
0 Jeff 24 180
1 Tom 25 165
2 Peter 20 179
  1. # 通过二维数组方式创建
  2. pd.DataFrame([[1,2,3], [4,5,6]], index=list("ab"), columns=list("fgh"))
  3. # 通过Series方式创建
  4. s1 = pd.Series({'name': 'jeff', 'age': 25})
  5. pd.DataFrame(s1, columns=['V'])
  6. pd.DataFrame(df['name']) # DataFrame每一列每一行都是一个Series
  7. pd.DataFrame(df.name)

常用操作

Pandas对DataFrame与Series提供了丰富的操作方法,在此列出最为常用的一些。

查看属性

  1. columns
  2. index
  3. dtypes
  4. shape
  5. size
  1. df.columns # Index(['name', 'age', 'height'], dtype='object')
  2. df.index # RangeIndex(start=0, stop=3, step=1)
  3. df.dtypes # 返回每一列的数据类型
  4. df.shape # (3, 3) # 返回元祖类型
  5. df.size # 9
  6. len(df) # 3
  7. df.shape[1] # 3

方法使用

  1. unique()
  2. value_counts()
  3. max/min/sum/mean
  4. describe
  5. head
  6. tail
  7. rename
  8. replace
  9. sort_values
  10. apply
  1. s1.unique() # array(['jeff', 25], dtype=object)
  2. s1.nunique() # 2 # 返回不同值的个数
  3. s1.value_counts() # 按照value值统计数量
  4. # 常见的数学运算
  5. df['height'].max() # 180 # min/max/sum/mean
  6. df['height'].describe() # 统计某一列的最大值,最小值,百分位数,平均数,标准差
  7. df.head(2)
  8. df.tail(4)
  9. # 重名了index和column,并且使它在原数据上生效
  10. df.rename(index={0: 'Hello', 1: 'World'}, columns={"name":"NAME","age":"AGE"}, inplace=True)
  11. # 将NAME这一列的Tom替换成Rehan,并且在原数据上生效
  12. df.replace({"NAME": {'Tom': 'Rehan'}}, inplace=True)
  13. # 将整个DataFrame中的数字165替换成185,并且在原数据上生效
  14. df.replace({165: 185}, inplace=True)

执行看下结果

NAME AGE height
Hello Jeff 24 180
World Rehan 25 185
2 Peter 20 179
  1. # 依照height和AGE这两列的数据降序排列,之后我们会学习sort_index函数
  2. df.sort_values(by=["height", "AGE"], ascending=False)

这里着重介绍下apply函数,其中有个参数叫axis(轴),返回的数据类型为Series。

  1. # 将每个数字加1了
  2. pd.Series([1,2,3]).apply(lambda s: s + 1)
  3. # 生成一个3行4列的二维数组
  4. d = np.array(range(12)).reshape(3, 4)
  5. dd = pd.DataFrame(d, columns=["a", "b", "c", "d"])
  6. # 纵向 每一列被当成一个Series传入
  7. dd.apply(lambda s: s[0] + 10000, axis=0) # 10000 10001 10002 10003
  8. # 横向 每一行被当成一个Series传入
  9. dd.apply(lambda s: s[0] + 10000, axis=1) # 10000 10004 10008
a b c d
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11

axis为0,表示index,纵向计算

axis为1,表示column,横向计算

dd.max(axis=0)                # 8 9 10 11     # 每一列的最大值
dd.max(axis=1)                # 3 7 11         # 每一行的最大值

数据选取/添加/删除

示例

这里简单介绍一下数据的基本操作,更加灵活的操作在介绍loc和iloc时会详细说明

# 列数据的选取
df = pd.DataFrame({"name":["Jeff", "Tom", "Peter"], "age": [24, 25, 20], "height": [180, 165, 179]})
df['name']                    # 选取一列
df[['name', 'age']]            # 选取多列
df.name                         # 不推荐这种写法

# 增加一列
df["class"] = 1

执行查看结果

name age height class
0 Jeff 24 180 1
1 Tom 25 165 1
2 Peter 20 179 1
# 删除某一列
del df["class"]

条件筛选

a = (df["age"] > 22) & (df["age"] < 25)
print(a)                                        # True False False(布尔型的Series)

# 下面这两条语句的执行结果是相同的
df[df["age"] == 24]
df[(df["age"] > 22) & (df["age"] < 25)]

执行看下结果

name age height
0 Jeff 24 180

Missing value

pandas使用numpy.nan来代表缺失值。缺失值不代表没有值,它本身就是某种类型的值。PYTHON中一般用None代表没有值,这与nan是两回事。缺失值不会被程序计算。处理的方式:

  1. 删除含有缺失值的行
  2. 填充缺失值

检测缺失值

这些常用方法,返回的都是布尔值

  • isna
  • notna
  • isnull
  • notnull
import numpy as np
a = pd.Series([1,3,np.nan,10,20])
pd.isna(a)                                # False False True False False
pd.notna(a)                             # True True False True True
pd.isnull(a)                            # False False True False False
pd.notnull(a)                            # True True False True True


# 注意:也可以这样用,这些方法对于Series和DataFrame是通用的
a.isna()
df['name'].isna()
df.isna()                                # 返回的是布尔型的二维数组

删除与填充

dropna函数,着重说明一下几个重要的参数。

axis为0时,按行删除,axis为1时,按列删除;

how为any时,表示该行/列只要有一个nan值,则删除;为all时,该行/列必须全部是nan值,才删除;

subset子集,可以用它来限定我们选定哪几行,或者哪几列,而不是应用到整个DataFrame;(axis=0时,subset指定列的集合,axis=1时,subset指定行的集合)

df_test = pd.DataFrame([[np.nan, 2, np.nan, 0], [3, 4, np.nan, 1],
                    [np.nan, np.nan, np.nan, 5]],
                  columns=list('ABCD'))


df_test.dropna(axis = 0)
df_test.dropna(axis = 1)
df_test.dropna(axis = 1,how = "all")
df_test.dropna(axis = 0,subset=['B'])

fillna函数,着重说明一下几个重要的参数。

axis为0时,按行来填充,axis为1时,按列来填充;

method参数,取值 bfill / backfill 时,用后一个值填充,取值ffill / pad 时,用前一个值填充

value参数,表示具体要填充的值

df.fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs)


# 表示age列的缺失值填充为18,name列的缺失值填充为Jeff
df.fillna({"age": 18, "name": "Jeff"})

Missing value的计算

要千万注意,缺失值是不参与计算的,所以清洗数据要仔细严谨一些

None == None                    # True
np.nan == np.nan                # False
np.nan + 3                        # nan

文本数据

DataFrame与Series中经常有文本格式的数据存在,pandas提供了良好的工具用来处理这些文本

str方法

str方法返回的对象才能够调用字符串处理函数

# 基本用法
a = pd.Series([' ABC', 'a ', 'xxx', 'fg'])
a.str.endswith('a')                    # False False False False


# 链式操作,原因在于每次计算结果返回的都是Series对象
a.str.strip().str.endswith('a')        # False True False False


# 去除index或者column名称前后的空格(很常见的一种用法)
df.columns = df.columns.str.strip()
# 注意,如果是应用到df.index,要确保index为字符串类型,否则会报错


# 截取/提取字符串,使用[]对字符串的位置进行索引选取
a = a.str.strip()
# 作用到了每一个字符串上
a.str[:1]                            # A a x f

Splitting and Replacing String

split方法用于根据某个分隔符对字符进行分割,返回一个列表

# 为了做分割练习,我们先修改下原数据
df['name'] = df['name'] + ' Wang'

执行结果

name age height
0 Jeff Wang 24 180
1 Tom Wang 25 165
2 Peter Wang 20 179
# 注意:这里的split返回的也是Series对象
df['name'].str.split(' ')                # [Jeff, Wang], [Tom, Wang], [Peter, Wang]

# 使用get去获取分割后的第一个元素           
df['name'].str.split(' ').str.get(0)    # Jeff Tom Peter

# 将name这一列分割成姓和名两列,结果是DataFrame类型了
df['name'].str.split(' ', expand=True)

上面单元格第三行代码的执行结果

0 1
0 Jeff Wang
1 Tom Wang
2 Peter Wang
# 获取分割后的第1列元素,并赋值给first name列
df['first name'] = df['name'].str.split(' ', expand=True)[0]
df

执行结果

name age height first name
0 Jeff Wang 24 180 Jeff
1 Tom Wang 25 165 Tom
2 Peter Wang 20 179 Peter

replace同Python中replace的用法大致相同,就不详细举例了

点击此处查看:str全部的可用函数

分类数据

分类数据对应的是统计学中的分类变量:拥有一些有限的值。比如说性别,iphone的类型(i5, i6, i7)等等。 分类的数据可以有序列性属性(即排序),但是不支持数值类型的操作。

常用的场景如下:

  1. 将一列拥有不是很多值的字符串变量转换成分类变量,可以节省内存
  2. 分类变量可以让数据有逻辑排序而不是词汇(词典)的排序,比如 one/two/three
  3. 和其它Python库交互时,它会被当做分类变量处理

创建分类特征

# 1. 创建Series时指定dtype
s = pd.Series(['i5', 'i6', 'i7', 'i5'], dtype='category')


# 2. astype强转
s = pd.Series(['excellent', 'great', 'good', 'excellent'])
s.astype('category')

df_test = pd.DataFrame({'A': ['a', 1, 2, 'a', 1, 'a']})
df_test['B'] = df_test['A'].astype('category')


# 3. 使用pd.Categorical创建
raw_cat = pd.Categorical(values=['apple', 'banana', 'apple', 'fruit', 'fruit', 'fruit'], 
                        categories=['apple', 'banana'], ordered=True)
print(raw_cat)
# 在赋值给DataFrame中的列时,要注意数量是要匹配的
df_test['C'] = raw_cat

执行看一下输出

[apple, banana, apple, NaN, NaN, NaN]
Categories (2, object): [apple < banana]

这里有几个要注意的点

categories指定要把哪些值设为分类值,而ordered为True时,则按照categories中给的顺序排序

不在categories中的变量会被置为NaN

# 4. 创建DataFrame时指定dtype,批量地将列转换成了分类数据
df_ = pd.DataFrame({"a": list("1234"), "b": list("5678")}, dtype='category')

控制分类值行为:CategoricalDtype

注意:前面创建分类数据的四种方式中,只有第三种方式显示的指明了有哪些类别,并且设置了排序;其余三种方式,都是由程序自动推断有哪些类别的,(也就是将数据中所有的唯一值都视为一种类别),也没有排序

“category”默认有两种分类值的行为:

  • 类别从数据中自行推断
  • 没有排序的性质

下面我们通过CategoricalDtype来控制分类值的这两类行为

categories参数,一个唯一值的序列并且不能有缺失值

ordered参数,是否排序,布尔类型

from pandas.api.types import CategoricalDtype

t = CategoricalDtype(categories=['b', 'a'], ordered=True)
pd.Series(['a', 'b', 'a', 'c'], dtype=t)
pd.Series(['a', 'b', 'a', 'c']).astype(t)

执行

0      a
1      b
2      a
3    NaN
dtype: category
Categories (2, object): [b < a]

注意:不在类别当中的数据会被视为NaN

分类值的描述

我们可以通过describe方法来查看分类数据的一些统计,比如count / unique / top / freq

先看一下我们之前的测试数据集

df_test['B']

执行

0    a
1    1
2    2
3    a
4    1
5    a
Name: B, dtype: category
Categories (3, object): [1, 2, a]

我们想看下该列数据调用describe方法的情况

df_test['B'].describe()

执行

count     6
unique    3
top       a
freq      3
Name: B, dtype: object

处理分类变量(属性和方法)

分类数据拥有分类与排序(唯二性)的特征:包含了分类值展示以及值之间是否是有序的。

我们可以通过 s.cat.categories 与 s.cat.ordered (这里的s是Series类型)进行操作。如果你没有人为的设定类别与排序信息,它们会被自动推断

# 返回分类类型
df_test['B'].cat.categories            # Index([1, 2, 'a'], dtype='object')

# 是否排序
df_test['B'].cat.ordered            # False

注意:categories 和方法 unique()返回的值可能是不一样的

from pandas.api.types import CategoricalDtype

s = pd.Series(list('babc')).astype(CategoricalDtype(list('abcd')))
s.cat.categories                # 有a, b, c, d四个类别
s.unique()                      # 只有b, a, c三个不同值

下面是一些分类变量涉及到的方法,增加类别、删除类别、移除无用类别、重新设置类别

单元格中的每行代码可逐行执行,查看结果

要注意的一点是:当添加已经存在的类别时会报错;删除不存在的类别时也会报错;(未更改源数据)

# 添加
df_test['B'].cat.add_categories(['b'])

# 删除
df_test['B'].cat.remove_categories(['a', 'b'])

# 移除没用的类别值
df_test['B'].cat.remove_unused_categories()

# 重新设定类别值,赋值的原因是我们后面会再次用到
df_test['B'] = df['B'].cat.set_categories([1, 2, 'a', 'b'], ordered=True)

严格意义上讲min和max并不算是数学运算,它只是获取了有序列表的头部和尾部

# 和我们前面给定的排序顺序一致
df_test['B'].min()          # 1
df_test['B'].max()          # a

df_test['B'].mean()            # 报错,分类变量不参与数学运算