数据分析三剑客之pandas(八)

pandas基础

pandas介绍

Python Data Analysis Library

pandas是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。Pandas 纳入 了大量库和一些标准的数据模型,提供了高效地操作大型结构化数据集所需的工具。

pandas核心数据结构

数据结构是计算机存储、组织数据的方式。 通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关。

Series

Series可以理解为一个一维的数组,只是index名称可以自己改动。类似于定长的有序字典,有Index和 value。

import pandas as pd
import numpy as np

# 创建一个空的系列
s = pd.Series()
# 从ndarray创建一个系列
data = np.array(['a','b','c','d'])
s = pd.Series(data)
0    a
1    b
2    c
3    d
s = pd.Series(data,index=[100,101,102,103])
100    a
101    b
102    c
103    d
# 从字典创建一个系列	
data = {'a' : 0., 'b' : 1., 'c' : 2.}
s = pd.Series(data)
a    0.0
b    1.0
c    2.0
# 从标量创建一个系列
s = pd.Series(5, index=[0, 1, 2, 3])
0    5
1    5
2    5
3    5

访问Series中的数据:

# 使用索引检索元素
s = pd.Series([1,2,3,4,5],index = ['a','b','c','d','e'])
a    1
b    2
c    3
d    4
e    5
print(s[0], s[:3], s[-3:])
1
---------------
a    1
b    2
c    3
---------------
c    3
d    4
e    5
# 使用标签检索数据
print(s['a'], s[['a','c','d']])
1
a    1
b    2
c    3

pandas日期处理

# pandas识别的日期字符串格式
dates = pd.Series(['2011', '2011-02', '2011-03-01', '2011/04/01', 
                   '2011/05/01 01:01:01', '01 Jun 2011'])
# to_datetime() 转换日期数据类型
dates = pd.to_datetime(dates)
print(dates, dates.dtype, type(dates))
print(dates.dt.day)
0   2011-01-01 00:00:00
1   2011-02-01 00:00:00
2   2011-03-01 00:00:00
3   2011-04-01 00:00:00
4   2011-05-01 01:01:01
5   2011-06-01 00:00:00
----------------------
datetime64[ns]
----------------------
<class 'pandas.core.series.Series'>
----------------------
0    1
1    1
2    1
3    1
4    1
5    1   
# datetime类型数据支持日期运算
delta = dates - pd.to_datetime('1970-01-01')
# 获取天数数值
print(delta.dt.days)
0    14975
1    15006
2    15034
3    15065
4    15095
5    15126

Series.dt提供了很多日期相关操作,如下:

Series.dt.year	The year of the datetime.
Series.dt.month	The month as January=1, December=12.
Series.dt.day	The days of the datetime.
Series.dt.hour	The hours of the datetime.
Series.dt.minute	The minutes of the datetime.
Series.dt.second	The seconds of the datetime.
Series.dt.microsecond	The microseconds of the datetime.
Series.dt.week	The week ordinal of the year.
Series.dt.weekofyear	The week ordinal of the year.
Series.dt.dayofweek	The day of the week with Monday=0, Sunday=6.
Series.dt.weekday	The day of the week with Monday=0, Sunday=6.
Series.dt.dayofyear	The ordinal day of the year.
Series.dt.quarter	The quarter of the date.
Series.dt.is_month_start	Indicates whether the date is the first day of the month.
Series.dt.is_month_end	Indicates whether the date is the last day of the month.
Series.dt.is_quarter_start	Indicator for whether the date is the first day of a quarter.
Series.dt.is_quarter_end	Indicator for whether the date is the last day of a quarter.
Series.dt.is_year_start	Indicate whether the date is the first day of a year.
Series.dt.is_year_end	Indicate whether the date is the last day of the year.
Series.dt.is_leap_year	Boolean indicator if the date belongs to a leap year.
Series.dt.days_in_month	The number of days in the month.

DateTimeIndex

通过指定周期和频率,使用date.range()函数就可以创建日期序列。 默认情况下,范围的频率是天。

import pandas as pd
# 以日为频率
datelist = pd.date_range('2019/08/21', periods=5)
print(datelist)
DatetimeIndex(['2019-08-21', '2019-08-22', '2019-08-23', '2019-08-24','2019-08-25'],
              dtype='datetime64[ns]', freq='D')
# 以月为频率
datelist = pd.date_range('2019/08/21', periods=5,freq='M')
print(datelist)
DatetimeIndex(['2019-08-31', '2019-09-30', '2019-10-31', '2019-11-30','2019-12-31'],
              dtype='datetime64[ns]', freq='M')
# 构建某个区间的时间序列
start = pd.datetime(2017, 11, 1)
end = pd.datetime(2017, 11, 5)
dates = pd.date_range(start, end)
print(dates)
DatetimeIndex(['2017-11-01', '2017-11-02', '2017-11-03', '2017-11-04','2017-11-05'],
              dtype='datetime64[ns]', freq='D')

bdate_range()用来表示商业日期范围,不同于date_range(),它不包括星期六和星期天。

import pandas as pd
datelist = pd.bdate_range('2011/11/03', periods=5)
print(datelist)
DatetimeIndex(['2011-11-03', '2011-11-04', '2011-11-07', '2011-11-08','2011-11-09'],
              dtype='datetime64[ns]', freq='B')

DataFrame

DataFrame是一个类似于表格的数据类型,可以理解为一个二维数组,索引有两个维度,可更改。DataFrame具有以下特点:

  • 潜在的列是不同的类型
  • 大小可变
  • 标记轴(行和列)
  • 可以对行和列执行算术运算
import pandas as pd

# 创建一个空的DataFrame
df = pd.DataFrame()
print(df)
Empty DataFrame
Columns: []
Index: []
# 从列表创建DataFrame
data = [1,2,3,4,5]
df = pd.DataFrame(data)
print(df)
   0
0  1
1  2
2  3
3  4
4  5
-----------------------
data = [['Alex',10],['Bob',12],['Clarke',13]]
df = pd.DataFrame(data,columns=['Name','Age'])
print(df)
     Name  Age
0    Alex   10
1     Bob   12
2  Clarke   13
------------------------
data = [['Alex',10],['Bob',12],['Clarke',13]]
df = pd.DataFrame(data,columns=['Name','Age'],dtype=float)
print(df)
 Name   Age
0    Alex  10.0
1     Bob  12.0
2  Clarke  13.0
--------------------------
data = [{'a': 1, 'b': 2},{'a': 5, 'b': 10, 'c': 20}]
df = pd.DataFrame(data)
print(df)
   a   b     c
0  1   2   NaN
1  5  10  20.0
--------------------------
# 从字典来创建DataFrame
data = {'Name':['Tom', 'Jack', 'Steve', 'Ricky'],'Age':[28,34,29,42]}
df = pd.DataFrame(data, index=['s1','s2','s3','s4'])
print(df)
     Name  Age
s1    Tom   28
s2   Jack   34
s3  Steve   29
s4  Ricky   42
--------------------------
data = {'one' : pd.Series([1, 2, 3], index=['a', 'b', 'c']), 'two' : pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])}
df = pd.DataFrame(data)
print(df)
   one  two
a  1.0    1
b  2.0    2
c  3.0    3
d  NaN    4

核心数据结构操作

列访问

DataFrame的单列数据为一个Series。根据DataFrame的定义可以 知晓DataFrame是一个带有标签的二维数组,每个标签相当每一列的列名。

import pandas as pd

d = {'one' : pd.Series([1, 2, 3], index=['a', 'b', 'c']),
     'two' : pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])}

df = pd.DataFrame(d)
print(df['one'])
print(df[['one', 'two']])

列添加

DataFrame添加一列的方法非常简单,只需要新建一个列索引。并对该索引下的数据进行赋值操作即可。

import pandas as pd

data = {'Name':['Tom', 'Jack', 'Steve', 'Ricky'],'Age':[28,34,29,42]}
df = pd.DataFrame(data, index=['s1','s2','s3','s4'])
df['score']=pd.Series([90, 80, 70, 60], index=['s1','s2','s3','s4'])
print(df)
     Name  Age  score
s1    Tom   28     90
s2   Jack   34     80
s3  Steve   29     70
s4  Ricky   42     60

列删除

删除某列数据需要用到pandas提供的方法pop,pop方法的用法如下:

import pandas as pd

d = {'one' : pd.Series([1, 2, 3], index=['a', 'b', 'c']), 
     'two' : pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd']), 
     'three' : pd.Series([10, 20, 30], index=['a', 'b', 'c'])}
df = pd.DataFrame(d)
print("dataframe is:")
print(df)

# 删除一列: one
del(df['one'])
print(df)

#调用pop方法删除一列
df.pop('two')
print(df)

行访问

如果只是需要访问DataFrame某几行数据的实现方式则采用数组的选取方式,使用 “:” 即可:

import pandas as pd

d = {'one' : pd.Series([1, 2, 3], index=['a', 'b', 'c']), 
    'two' : pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])}

df = pd.DataFrame(d)
print(df[2:4])

loc方法是针对DataFrame索引名称的切片方法。loc方法使用方法如下:

import pandas as pd

d = {'one' : pd.Series([1, 2, 3], index=['a', 'b', 'c']), 
     'two' : pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])}

df = pd.DataFrame(d)
print(df.loc['b'])
one    2.0
two    2.0
---------------------
print(df.loc[['a', 'b']])
   one  two
a  1.0    1
b  2.0    2


iloc和loc区别是iloc接收的必须是行索引和列索引的位置。iloc方法的使用方法如下:

import pandas as pd

d = {'one' : pd.Series([1, 2, 3], index=['a', 'b', 'c']),
     'two' : pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])}

df = pd.DataFrame(d)
print(df.iloc[2])
one    3.0
two    3.0
print(df.iloc[[2, 3]])
one  two
c  3.0    3
d  NaN    4


行添加

import pandas as pd

df = pd.DataFrame([['zs', 12], ['ls', 4]], columns = ['Name','Age'])
df2 = pd.DataFrame([['ww', 16], ['zl', 8]], columns = ['Name','Age'])

df = df.append(df2)
print(df)

行删除

使用索引标签从DataFrame中删除或删除行。 如果标签重复,则会删除多行。

import pandas as pd

df = pd.DataFrame([['zs', 12], ['ls', 4]], columns = ['Name','Age'])
df2 = pd.DataFrame([['ww', 16], ['zl', 8]], columns = ['Name','Age'])
df = df.append(df2)
Name  Age
0   zs   12
1   ls    4
0   ww   16
1   zl    8
------------------
# 删除index为0的行
df = df.drop(0)
print(df)
  Name  Age
1   ls    4
1   zl    8

修改DataFrame中的数据

更改DataFrame中的数据,原理是将这部分数据提取出来,重新赋值为新的数据。

import pandas as pd

df = pd.DataFrame([['zs', 12], ['ls', 4]], columns = ['Name','Age'])
df2 = pd.DataFrame([['ww', 16], ['zl', 8]], columns = ['Name','Age'])
df = df.append(df2)
df['Name'][0] = 'Tom'
print(df)

DataFrame常用属性

编号 属性或方法 描述
1 axes 返回 行/列 标签(index)列表。
2 dtype 返回对象的数据类型(dtype)。
3 empty 如果系列为空,则返回True
4 ndim 返回底层数据的维数,默认定义:1
5 size 返回基础数据中的元素数。
6 values 将系列作为ndarray返回。
7 head(n) 返回前n行。
8 tail(n) 返回最后n行。

实例代码:

import pandas as pd

data = {'Name':['Tom', 'Jack', 'Steve', 'Ricky'],'Age':[28,34,29,42]}
df = pd.DataFrame(data, index=['s1','s2','s3','s4'])
df['score']=pd.Series([90, 80, 70, 60], index=['s1','s2','s3','s4'])
print(df)
print(df.axes)
print(df['Age'].dtype)
print(df.empty)
print(df.ndim)
print(df.size)
print(df.values)
print(df.head(3)) # df的前三行
print(df.tail(3)) # df的后三行

Jupyter notebook

Jupyter Notebook(此前被称为 IPython notebook)是一个交互式笔记本,支持运行 40 多种编程语言。使用浏览器作为界面,向后台的IPython服务器发送请求,并显示结果。 Jupyter Notebook 的本质是一个 Web 应用程序,便于创建和共享文学化程序文档,支持实时代码,数学方程,可视化和 markdown。

IPython 是一个 python 的交互式 shell,比默认的python shell 好用得多,支持变量自动补全,自动缩进,支持 bash shell 命令,内置了许多很有用的功能和函数。

安装ipython

windows: 前提是有numpy,matplotlib pandas

​ 采用pip安装 pip install ipython

OS X: AppStore下载安装苹果开发工具Xcode。

​ 使用easy_install或pip安装IPython,或者从源文件安装。

安装Jupyter notebook

pip3 install jupyter

启动Jupyter notebook

找到一个工作目录,运行命令:
jupyter notebook

pandas核心

pandas描述性统计

数值型数据的描述性统计主要包括了计算数值型数据的完整情况、最小值、均值、中位 数、最大值、四分位数、极差、标准差、方差、协方差等。在NumPy库中一些常用的统计学函数也可用于对数据框进行描述性统计。

np.min	最小值 
np.max	最大值 
np.mean	均值 
np.ptp	极差 
np.median	中位数 
np.std	标准差 
np.var	方差 
np.cov	协方差

实例:

import pandas as pd
import numpy as np

# 创建DF
d = {'Name':pd.Series(['Tom','James','Ricky','Vin','Steve','Minsu','Jack', 'Lee', 'David', 'Gasper', 'Betina', 'Andres']),
  'Age':pd.Series([25,26,25,23,30,29,23,34,40,30,51,46]),
   'Rating':pd.Series([4.23,3.24,3.98,2.56,3.20,4.6,3.8,3.78,2.98,4.80,4.10,3.65])}

df = pd.DataFrame(d)
print(df)
# 测试描述性统计函数
print(df.sum()) 总年龄  总分数
print(df.sum(1)) 对应的分数和年龄相加
0      29.23
1      29.24
2      28.98
3      25.56
4      33.20
5      33.60
6     226.80
7      37.78
8      42.98
9      34.80
10     55.10
11     49.65
print(df.mean()) 年龄平均值  分数平均值
print(df.mean(1)) 对应分数和年龄的平均值

pandas提供了统计相关函数:

1 count() 非空观测数量
2 sum() 所有值之和
3 mean() 所有值的平均值
4 median() 所有值的中位数
5 std() 值的标准偏差
6 min() 所有值中的最小值
7 max() 所有值中的最大值
8 abs() 绝对值
9 prod() 数组元素的乘积
10 cumsum() 累计总和
11 cumprod() 累计乘积

pandas还提供了一个方法叫作describe,能够一次性得出数据框所有数值型特征的非空值数目、均值、标准差等。

import pandas as pd
import numpy as np

#Create a Dictionary of series
d = {'Name':pd.Series(['Tom','James','Ricky','Vin','Steve','Minsu','Jack',
   'Lee','David','Gasper','Betina','Andres']),
   'Age':pd.Series([25,26,25,23,30,29,23,34,40,30,51,46]),
   'Rating':pd.Series([4.23,3.24,3.98,2.56,3.20,4.6,3.8,3.78,2.98,4.80,4.10,3.65])}

#Create a DataFrame
df = pd.DataFrame(d)
print(df.describe())
            Age      Rating
count   12.000000  12.000000
mean    48.500000   3.743333
std     55.653963   0.661628
min     23.000000   2.560000
25%     25.750000   3.230000
50%     30.000000   3.790000
75%     41.500000   4.132500
max    223.000000   4.800000
25%, 50%75%是对应的四分位数。
四分位数(Quartile)是指在统计学中把所有数值由小到大排列并分成四等份,处于三个分割点位置的数值。
第一四分位数 (Q1),又称“较小四分位数”,等于该样本中所有数值由小到大排列后第25%的数字。
第二四分位数 (Q2),又称“中位数”,等于该样本中所有数值由小到大排列后第50%的数字。
第三四分位数 (Q3),又称“较大四分位数”,等于该样本中所有数值由小到大排列后第75%的数字。
第三四分位数与第一四分位数的差距又称四分位距(InterQuartile Range,IQR)。
----------------------------------------------
print(df.describe(include=['object']))
		  name
count      12
unique     12
top     Minsu
freq        1
print(df.describe(include=['number']))
            Age     Rating
count   12.000000  12.000000
mean    48.500000   3.743333
std     55.653963   0.661628
min     23.000000   2.560000
25%     25.750000   3.230000
50%     30.000000   3.790000
75%     41.500000   4.132500
max    223.000000   4.800000

pandas排序

Pandas有两种排序方式,它们分别是按标签与按实际值排序。

import pandas as pd
import numpy as np

unsorted_df=pd.DataFrame(np.random.randn(10,2),
                         index=[1,4,6,2,3,5,9,8,0,7],columns=['col2','col1'])
print(unsorted_df)
      col2      col1
1  0.435566  1.821756
4  0.602952 -0.795613
6  1.631176  0.497051
2 -1.751020 -0.229628
3 -0.215565  0.602035
5 -0.410899 -0.435106
9  0.718550  0.165660
8 -0.373403  0.872213
0 -0.243545 -0.321679
7  0.617333 -0.189663

按行标签排序

使用sort_index()方法,通过传递axis参数和排序顺序,可以对DataFrame进行排序。 默认情况下,按照升序对行标签进行排序。

import pandas as pd
import numpy as np

# 按照行标进行排序
sorted_df=unsorted_df.sort_index()
print (sorted_df)
     col2      col1
0 -0.798315  1.216546
1  0.395530  0.025233
2 -0.880199 -0.936372
3  0.610572  0.118816
4 -0.406779  0.873662
5 -0.343186 -0.822493
6 -0.637138  0.830524
7 -0.241964  0.339942
8  0.775675  2.003242
9 -0.911961 -0.061606
-----------------------
# 控制排序顺序
sorted_df = unsorted_df.sort_index(ascending=False)
print (sorted_df)
     col2      col1
9  0.575977 -0.359740
8 -0.253888 -1.466810
7 -1.255561  0.325737
6  0.870994  0.875937
5 -0.809964 -2.042410
4  0.134664 -0.480342
3 -0.978605  0.301837
2  0.879021 -0.154140
1  1.692807  0.502087
0 -1.300620  0.035543

按列标签排序

import numpy as np

d = {'Name':pd.Series(['Tom','James','Ricky','Vin','Steve','Minsu','Jack',
   'Lee','David','Gasper','Betina','Andres']),
   'Age':pd.Series([25,26,25,23,30,29,23,34,40,30,51,46]),
   'Rating':pd.Series([4.23,3.24,3.98,2.56,3.20,4.6,3.8,3.78,2.98,4.80,4.10,3.65])}
unsorted_df = pd.DataFrame(d)
      Name  Age  Rating
0      Tom   25    4.23
1    James   26    3.24
2    Ricky   25    3.98
3      Vin   23    2.56
4    Steve   30    3.20
5    Minsu   29    4.60
6     Jack   23    3.80
7      Lee   34    3.78
8    David   40    2.98
9   Gasper   30    4.80
10  Betina   51    4.10
11  Andres   46    3.65
# 按照列标签进行排序
sorted_df=unsorted_df.sort_index(axis=1)
print (sorted_df)
    Age    Name  Rating
0    25     Tom    4.23
1    26   James    3.24
2    25   Ricky    3.98
3    23     Vin    2.56
4    30   Steve    3.20
5    29   Minsu    4.60
6    23    Jack    3.80
7    34     Lee    3.78
8    40   David    2.98
9    30  Gasper    4.80
10   51  Betina    4.10
11   46  Andres    3.65

按某列值排序

像索引排序一样,sort_values()是按值排序的方法。它接受一个by参数,它将使用要与其排序值的DataFrame的列名称。

import pandas as pd
import numpy as np

d = {'Name':pd.Series(['Tom','James','Ricky','Vin','Steve','Minsu','Jack',
   'Lee','David','Gasper','Betina','Andres']),
   'Age':pd.Series([25,26,25,23,30,29,23,34,40,30,51,46]),
   'Rating':pd.Series([4.23,3.24,3.98,2.56,3.20,4.6,3.8,3.78,2.98,4.80,4.10,3.65])}
unsorted_df = pd.DataFrame(d)
# 按照年龄进行排序
sorted_df = unsorted_df.sort_values(by='Age')
print (sorted_df)
# 先按Age进行升序排序,然后按Rating降序排序
sorted_df = unsorted_df.sort_values(by=['Age', 'Rating'], ascending=[True, False])
print (sorted_df)

pandas分组

在许多情况下,我们将数据分成多个集合,并在每个子集上应用一些函数。在应用函数中,可以执行以下操作 :

  • 聚合 - 计算汇总统计
  • 转换 - 执行一些特定于组的操作
  • 过滤 - 在某些情况下丢弃数据
import pandas as pd

ipl_data = {'Team': ['Riders', 'Riders', 'Devils', 'Devils', 'Kings',
         'kings', 'Kings', 'Kings', 'Riders', 'Royals', 'Royals', 'Riders'],
         'Rank': [1, 2, 2, 3, 3,4 ,1 ,1,2 , 4,1,2],
         'Year': [2014,2015,2014,2015,2014,2015,2016,2017,2016,2014,2015,2017],
         'Points':[876,789,863,673,741,812,756,788,694,701,804,690]}
df = pd.DataFrame(ipl_data)
print(df)

将数据拆分成组

# 按照年份Year字段分组
print (df.groupby('Year'))
# 查看分组结果
print (df.groupby('Year').groups)

迭代遍历分组

groupby返回可迭代对象,可以使用for循环遍历:

grouped = df.groupby('Year')
# 遍历每个分组
for year,group in grouped:
    print (year)
2014
2015
2016
2017
    print (group)
Team  Rank  Year  Points
0  Riders     1  2014     876
2  Devils     2  2014     863
4   Kings     3  2014     741
9  Royals     4  2014     701
      Team  Rank  Year  Points
1   Riders     2  2015     789
3   Devils     3  2015     673
5    kings     4  2015     812
10  Royals     1  2015     804
     Team  Rank  Year  Points
6   Kings     1  2016     756
8  Riders     2  2016     694
      Team  Rank  Year  Points
7    Kings     1  2017     788
11  Riders     2  2017     690
  

获得一个分组细节

grouped = df.groupby('Year')
print (grouped.get_group(2014))

分组聚合

聚合函数为每个组返回聚合值。当创建了分组(group by)对象,就可以对每个分组数据执行求和、求标准差等操作。

# 聚合每一年的平均的分
grouped = df.groupby('Year')
print (grouped['Points'].agg(np.mean))
Year
2014    795.25
2015    769.50
2016    725.00
2017    739.00
Name: Points, dtype: float64
# 聚合每一年的分数之和、平均分、标准差
grouped = df.groupby('Year')
agg = grouped['Points'].agg([np.sum, np.mean, np.std])
print (agg)
Year                         
2014  3181  795.25  87.439026
2015  3078  769.50  65.035888
2016  1450  725.00  43.840620
2017  1478  739.00  69.296465


pandas数据表关联操作

Pandas具有功能全面的高性能内存中连接操作,与SQL等关系数据库非常相似。
Pandas提供了一个单独的merge()函数,作为DataFrame对象之间所有标准数据库连接操作的入口。

合并两个DataFrame:

import pandas as pd
left = pd.DataFrame({
         'student_id':[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],
         'student_name': ['Alex', 'Amy', 'Allen', 'Alice', 'Ayoung', 'Billy', 'Brian', 'Bran', 'Bryce', 'Betty', 'Emma', 'Marry', 'Allen', 'Jean', 'Rose', 'David', 'Tom', 'Jack', 'Daniel', 'Andrew'],
         'class_id':[1,1,1,2,2,2,3,3,3,4,1,1,1,2,2,2,3,3,3,2], 
         'gender':['M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F'], 
         'age':[20,21,22,20,21,22,23,20,21,22,20,21,22,23,20,21,22,20,21,22], 
         'score':[98,74,67,38,65,29,32,34,85,64,52,38,26,89,68,46,32,78,79,87]})
right = pd.DataFrame(
         {'class_id':[1,2,3,5],
         'class_name': ['ClassA', 'ClassB', 'ClassC', 'ClassE']})
# 合并两个DataFrame
data = pd.merge(left,right)
print(data)
student_id student_name  class_id gender  age  score class_name


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fhgPCkTG-1585033207034)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\1578212720413.png)]

使用“how”参数合并DataFrame:

# 合并两个DataFrame (左连接)
rs = pd.merge(left, right, how='left')
print(rs)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qvCIDnmB-1585033207034)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\1578212847471.png)]

其他合并方法同数据库相同:

合并方法 SQL等效 描述
left LEFT OUTER JOIN 使用左侧对象的键
right RIGHT OUTER JOIN 使用右侧对象的键
outer FULL OUTER JOIN 使用键的联合
inner INNER JOIN 使用键的交集

试验:

# 合并两个DataFrame (右连接)
rs = pd.merge(left,right,on='subject_id', how='right')
print(rs)

# 合并两个DataFrame (外连接)
rs = pd.merge(left,right,on='subject_id', how='outer')
print(rs)
# 合并两个DataFrame (内连接)
rs = pd.merge(left,right,on='subject_id', how='inner')
print(rs)

rs = pd.merge(left,right,on='subject_id', how='right')
print(rs)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0oAJW6kE-1585033207035)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\1578212984252.png)]

# 合并两个DataFrame (外连接)
rs = pd.merge(left,right,on='subject_id', how='outer')
print(rs)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bl7Y1hOi-1585033207036)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\1578213156629.png)]

pandas透视表与交叉表

有如下数据:

import pandas as pd
left = pd.DataFrame({
         'student_id':[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],
         'student_name': ['Alex', 'Amy', 'Allen', 'Alice', 'Ayoung', 'Billy', 'Brian', 'Bran', 'Bryce', 'Betty', 'Emma', 'Marry', 'Allen', 'Jean', 'Rose', 'David', 'Tom', 'Jack', 'Daniel', 'Andrew'],
         'class_id':[1,1,1,2,2,2,3,3,3,4,1,1,1,2,2,2,3,3,3,2], 
         'gender':['M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F'], 
         'age':[20,21,22,20,21,22,23,20,21,22,20,21,22,23,20,21,22,20,21,22], 
         'score':[98,74,67,38,65,29,32,34,85,64,52,38,26,89,68,46,32,78,79,87]})
right = pd.DataFrame(
         {'class_id':[1,2,3,5],
         'class_name': ['ClassA', 'ClassB', 'ClassC', 'ClassE']})
# 合并两个DataFrame
data = pd.merge(left,right)
print(data)

透视表

透视表(pivot table)是各种电子表格程序和其他数据分析软件中一种常见的数据汇总工具。它根据一个或多个键对数据进行分组聚合,并根据每个分组进行数据汇总

# 以class_id与gender做分组汇总数据,默认聚合统计所有列
print(data.pivot_table(index=['class_id', 'gender']))
                    age      score      student_id
class_id gender                                  
1        F       21.000000  52.333333    8.666667
         M       21.000000  66.000000    5.333333
2        F       20.750000  59.750000   13.750000
         M       22.000000  61.000000    8.333333
3        F       21.333333  48.333333   11.333333
         M       21.000000  65.000000   14.666667
# 以class_id与gender做分组汇总数据,聚合统计score列
print(data.pivot_table(index=['class_id', 'gender'], values=['score']))
                  score
class_id gender           
1        F       52.333333
         M       66.000000
2        F       59.750000
         M       61.000000
3        F       48.333333
         M       65.000000
# 以class_id与gender做分组汇总数据,聚合统计score列,针对age的每个值列级分组统计
print(data.pivot_table(index=['class_id', 'gender'], values=['score'], columns=['age']))
                 score                  
age                20    21    22    23
class_id gender                        
1        F       52.0  38.0  67.0   NaN
         M       98.0  74.0  26.0   NaN
2        F       53.0  46.0  87.0   NaN
         M        NaN  65.0  29.0  89.0
3        F       34.0  79.0   NaN  32.0
         M       78.0  85.0  32.0   NaN
# 以class_id与gender做分组汇总数据,聚合统计score列,针对age的每个值列级分组统计,添加行、列小计
print(data.pivot_table(index=['class_id', 'gender'], values=['score'], 
                       columns=['age'], margins=True))

                 score                             
age                     20    21    22    23        All
class_id gender                                        
1        F       52.000000  38.0  67.0   NaN  52.333333
         M       98.000000  74.0  26.0   NaN  66.000000
2        F       53.000000  46.0  87.0   NaN  59.750000
         M             NaN  65.0  29.0  89.0  61.000000
3        F       34.000000  79.0   NaN  32.0  48.333333
         M       78.000000  85.0  32.0   NaN  65.000000
All              61.333333  64.5  48.2  60.5  58.789474
# 以class_id与gender做分组汇总数据,聚合统计score列,针对age的每个值列级分组统计,添加行、列小计
print(data.pivot_table(index=['class_id', 'gender'], values=['score'], columns=['age'], margins=True, aggfunc='max'))
                 
                 score                      
age                20    21    22    23 All
class_id gender                            
1        F       52.0  38.0  67.0   NaN  67
         M       98.0  74.0  26.0   NaN  98
2        F       68.0  46.0  87.0   NaN  87
         M        NaN  65.0  29.0  89.0  89
3        F       34.0  79.0   NaN  32.0  79
         M       78.0  85.0  32.0   NaN  85
All              98.0  85.0  87.0  89.0  98


交叉表

交叉表(cross-tabulation, 简称crosstab)是一种用于计算分组频率的特殊透视表

# 按照class_id分组,针对不同的gender,统计数量
print(pd.crosstab(data.class_id, data.gender, margins=True))
gender     F  M  All
class_id            
1          3  3    6
2          4  3    7
3          3  3    6
All       10  9   19

pandas可视化

基本绘图:绘图

import pandas as pd
import numpy as np
import matplotlib.pyplot as mp 

df = pd.DataFrame(np.random.randn(10,4),index=pd.date_range('2018/12/18',
   periods=10), columns=list('ABCD'))
df.plot()
mp.show()

plot方法允许除默认线图之外的少数绘图样式。 这些方法可以作为plot()kind关键字参数。这些包括 :

  • barbarh为条形
  • hist为直方图
  • scatter为散点图

条形图

df = pd.DataFrame(np.random.rand(10,4),columns=['a','b','c','d'])
df.plot.bar()
# df.plot.bar(stacked=True)
mp.show()

直方图

df = pd.DataFrame()
df['a'] = pd.Series(np.random.normal(0, 1, 1000)-1)
df['b'] = pd.Series(np.random.normal(0, 1, 1000))
df['c'] = pd.Series(np.random.normal(0, 1, 1000)+1)
print(df)
df.plot.hist(bins=20) #要使用的直方图bins箱数
mp.show()

散点图

df = pd.DataFrame(np.random.rand(50, 4), columns=['a', 'b', 'c', 'd'])
df.plot.scatter(x='a', y='b')
mp.show()

饼状图

df = pd.DataFrame(3 * np.random.rand(4), index=['a', 'b', 'c', 'd'], columns=['x'])
df.plot.pie(subplots=True)
mp.show()

数据读取与存储

读取与存储csv:

# filepath 文件路径。该字符串可以是一个URL。有效的URL方案包括http,ftp和file 
# sep 分隔符。read_csv默认为“,”,read_table默认为制表符“[Tab]”。
# header 接收int或sequence。表示将某行数据作为列名。默认为infer,表示自动识别。
# names 接收array。表示列名。
# index_col 表示索引列的位置,取值为sequence则代表多重索引。 
# dtype 代表写入的数据类型(列名为key,数据格式为values)。
# engine 接收c或者python。代表数据解析引擎。默认为c。
# nrows 接收int。表示读取前n行。

pd.read_table(
    filepath_or_buffer, sep='\t', header='infer', names=None, 
    index_col=None, dtype=None, engine=None, nrows=None) 
pd.read_csv(
    filepath_or_buffer, sep=',', header='infer', names=None, 
    index_col=None, dtype=None, engine=None, nrows=None)

DataFrame.to_csv(excel_writer=None, sheetname=None, header=True, index=True, index_label=None, mode=’w’, encoding=None) 

读取与存储excel:

# io 表示文件路径。
# sheetname 代表excel表内数据的分表位置。默认为0。 
# header 接收int或sequence。表示将某行数据作为列名。默认为infer,表示自动识别。
# names 表示索引列的位置,取值为sequence则代表多重索引。
# index_col 表示索引列的位置,取值为sequence则代表多重索引。
# dtype 接收dict。数据类型。
pandas.read_excel(io, sheetname=0, header=0, index_col=None, names=None, dtype=None)

DataFrame.to_excel(excel_writer=None, sheetname=None, header=True, index=True, index_label=None, mode=’w’, encoding=None) 

读取与存储JSON:

# 通过json模块转换为字典,再转换为DataFrame
pd.read_json('../ratings.json')

movielens电影评分数据分析

需求如下:

  1. 读取数据,从用户表读取用户信息、同样方法,导入电影评分表、电影数据表。
  2. 合并数据表
  3. 对数据初步描述分析
  4. 查看每一部电影不同性别的平均评分并计算分歧差值,之后排序
  5. 算出每部电影平均得分并对其进行排序
  6. 查看评分次数多的电影并进行排序
  7. 过滤掉评分条目数不足250条的电影
  8. 评分最高的十部电影
  9. 查看不同年龄的分布情况并且采用直方图进行可视化
  10. 在原数据中标记出用户位于的年龄分组
  11. 可视化显示movies_ratings中不同类型电影的频数

相关API补充

1.与bins有关的两个函数pd.cut()和pd.qcut()

#qcut是根据这些值的频率来选择箱子的均匀间隔每个箱子中含有的数的数量是相同的
#cut将根据值本身来选择箱子均匀间隔,即每个箱子的间距都是相同的

pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False)

用途:返回 x 中的每一个数据 在bins 中对应 的范围
参数:
x : 必须是一维数据
bins: 不同面元(不同范围)类型:整数,序列如数组, 和IntervalIndex
right: 最后一个bins是否包含最右边的数据,默认为True
precision:精度 默认保留三位小数
retbins: 即return bins 是否返回每一个bins的范围 默认为False


假如我们有一组学生成绩,我们需要将这些成绩分为不及格(0-59)、及格(60-70)、良(71-85)、优(86-100)这几组。这时候可以用到cut()

import numpy as np
import pandas as pd
# 我们先给 scores传入30个从0到100随机的数
scores = np.random.uniform(0,100,size=30)
# 然后使用 np.round()函数控制数据精度
scores = np.round(scores,1)
# 指定分箱的区间
grades = [0,59,70,85,100]
cuts = pd.cut(scores,grades)
print(cuts)
[(0, 59], (0, 59], (85, 100], (0, 59], (59, 70], ..., (0, 59], (0, 59], (0, 59], (0, 59], (0, 59]]
Length: 30
Categories (4, interval[int64]): [(0, 59] < (59, 70] < (70, 85] < (85, 100]]
print(pd.value_counts(cuts))
(0, 59]      17
(70, 85]      8
(59, 70]      4
(85, 100]     1                                 默认情况下,cat()的区间划分是左开右闭,可以传递right=False来改变哪一边是封闭的                     cuts = pd.cut(scores,grades,right=False)         group_names = ['不及格','及格','良','优秀']
cuts = pd.cut(scores,grades,labels=group_names) # 将成绩均匀的分在四个箱子中,precision=2的选项将精度控制在两位
cuts = pd.cut(scores,4,precision=2)                      


qcut()可以生成指定的箱子数,然后使每个箱子都具有相同数量的数据

import numpy as np
import pandas as pd
# 正态分布
data = np.random.randn(100)
# 分四个箱子
cuts = pd.qcut(data,4)
print(cuts)
print(pd.value_counts(cuts))

======output:======

cuts:
[(-0.745, -0.0723], (0.889, 2.834], (-0.745, -0.0723], (0.889, 2.834], (0.889, 2.834], ..., (-0.745, -0.0723], (-0.0723, 0.889], (-3.1599999999999997, -0.745], (-0.745, -0.0723], (-0.0723, 0.889]]
Length: 100
Categories (4, interval[float64]): [(-3.1599999999999997, -0.745] < (-0.745, -0.0723] < (-0.0723, 0.889] <
                                    (0.889, 2.834]]

cuts.value_counts:
(0.889, 2.834]                   25
(-0.0723, 0.889]                 25
(-0.745, -0.0723]                25
(-3.1599999999999997, -0.745]    25
dtype: int64


2.value_counts()与values

对Series里面的每个值进行计数并且排序
value_counts( )返回的结果是一个Series数组,可以跟别的数组进行运算。
value_counts()是Series拥有的方法,一般在DataFrame中使用时,需要指定对哪一列或行使用
value_count() 的参数:

(1) normalize : boolean, default False             如果为True,则返回的对象将包含唯一值的相对频率。
sort : boolean, default True             按值排序
ascending : boolean, default False        按频率计数升序排序
bins : integer, optional    而不是数值计算,把它们分成半开放的箱子,一个方便的pd.cut,只适用于数字数据
dropna : boolean, default True          不包括NaN的数量。


df.column.values   以array形式返回指定column的所有取值

3.take()

take()函数接受一个索引列表,用数字表示,使得df根据列表中索引的顺序进行排序

ser=pd.Series(list('abcdefghijklmnopqrstuvwxyz'))
pos = [0, 4, 8, 14, 20]
ser.take(pos)
0     a
4     e
8     i
14    o
20    u
dtype: object

4.pandas的拼接分为两种:
级联:pd.concat, pd.append
合并:pd.merge, pd.join

5.map()函数:新建一列

注意 map()中不能使用sum之类的函数,for循环

map是Series的一个函数
  map()可以映射新一列数据
  map()中可以使用lambd表达式
  map()中可以使用方法,可以是自定义的方法

df = pd.DataFrame(data[['zhangsan',1000,'sale'],
                        ['lisi',2000,'dev'],                             ['wangwu',3333,'dev']],
                  columns=                                               ['name','salary','dep'])
df['e_name']=df['name'].map({'lisi':'Tony','zhangsan':'Tom','wangwu':'Jerry'})
print(df)
      name   salary  dep   e_name
0  zhangsan    1000  sale    Tom
1      lisi    2000   dev   Tony
2    wangwu    3333   dev  Jerry

6.删除重复元素duplicated()

使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True(是重复的)

  • 使用drop_duplicates()函数删除重复的行

  • 使用duplicate()函数查看重复的行

data = [[100,100,100],[90,90,88],[100,100,100],[90,90,87],[100,100,100]]
columns = ['python','c++','java']
index = list('ABCDE')
df = DataFrame(data=data,index=index,columns=columns)
df.duplicated(keep="first") # 告诉我们 当前行是否重复
# 参数默认是 keep="first" 保留开始的 意思是如果发现很多重复的元素 第一个不算重复的 后面的才是 某一行重复 就返回True
结果为:
A    False
B    False
C     True
D    False
E     True
dtype: bool
df.duplicated(keep="last") # keep last 如果遇到重复的元素 最后一个不算重复的 前面的才算重复 这一行重复了 就是True
结果为:
A     True
B    False
C     True
D    False
E    False
dtype: bool
df.duplicated(keep=False) # 只要有和别人完全一样的 不管在开头还是结尾 都算重复 这一行如果是重复的就返回 True
结果为:
A     True
B    False
C     True
D    False
E     True
dtype: bool

append  连接另一个index对象,产生一个新的index
diff  计算差集,并得到一个index
intersection  计算交集
union  计算并集
isin  计算一个指示各值是否都包含在参数集合中的布尔型数组
delete  删除索引i处的元素,并得到新的index
drop  删除传入的值,并得到新的index
insert  将元素插入到索引i处,并得到新的index
is_monnotonic  当各元素均大于等于前一个元素时,返回True
is_unique  当index没有重复值时,返回True
unique  计算index中唯一值的数组

7.loc与iloc

loc是基于label进行索引的!

import pandas as pd
df1 = pd.DataFrame(data= [[1, 2, 3],[4, 5, 6], [7, 8, 9]], index=[0, 1, 2], columns=['a','b','c'])
df2 = pd.DataFrame(data= [[1, 2, 3],[4, 5, 6], [7, 8, 9]], index=['e', 'f', 'g'], columns=['a','b','c'])
print(df1)
print(df2)
'''
df1:
   a  b  c
0  1  2  3
1  4  5  6
2  7  8  9
df2:
   a  b  c
e  1  2  3
f  4  5  6
g  7  8  9
'''
# loc索引行,label是整型数字
print(df1.loc[0])
'''
a    1
b    2
c    3
Name: 0, dtype: int64
'''
# loc索引行,label是字符型
print(df2.loc['e'])
'''
a    1
b    2
c    3
Name: 0, dtype: int64
'''
# 如果对df2这么写:df2.loc[0]会报错,因为loc索引的是label,显然在df2的行的名字中没有叫0的。
print(df2.loc[0])
'''
TypeError: cannot do slice indexing on <class 'pandas.core.indexes.base.Index'> with these indexers [0] of <class 'int'>
'''
 
# loc索引多行数据
print(df1.loc[1:])
'''
   a  b  c
1  4  5  6
2  7  8  9
'''
 
# loc索引多列数据
print(df1.loc[:,['a', 'b']])
'''
   a  b
0  1  2
1  4  5
2  7  8
'''
# df1.loc[:,0:2]这么写报错, 因为loc索引的是label,显然在df1的列的名字中没有叫0,1和2的。
print(df1.loc[:,0:2])
'''
TypeError: cannot do slice indexing on <class 'pandas.core.indexes.base.Index'> with these indexers [0] of <class 'int'>
'''
 
# loc索引某些行某些列
print(df1.loc[0:2, ['a', 'b']])
'''
   a  b
0  1  2
1  4  5
2  7  8
'''

其实,对于iloc始终坚持一个原则:**iloc是基于position进行索引的!**i即index的简写

import pandas as pd
df1 = pd.DataFrame(data= [[1, 2, 3],[4, 5, 6], [7, 8, 9]], index=[0, 1, 2], columns=['a','b','c'])
df2 = pd.DataFrame(data= [[1, 2, 3],[4, 5, 6], [7, 8, 9]], index=['e', 'f', 'g'], columns=['a','b','c'])
print(df1)
print(df2)
'''
df1:
   a  b  c
0  1  2  3
1  4  5  6
2  7  8  9
df2:
   a  b  c
e  1  2  3
f  4  5  6
g  7  8  9
'''
# iloc索引行,label是整型数字
print(df1.iloc[0])
'''
a    1
b    2
c    3
Name: 0, dtype: int64
'''
 
# iloc索引行,label是字符型。如果按照loc的写法来写应该是:df2.iloc['e'],显然这样报错,因为iloc不认识label,它是基于位置的。
print(df2.iloc['e'])
'''
TypeError: cannot do positional indexing on <class 'pandas.core.indexes.base.Index'> with these indexers [e] of <class 'str'>
'''
# iloc索引行,label是字符型。正确的写法应该如下:
# 也就说,不论index是什么类型的,iloc只能写位置,也就是整型数字。
print(df2.iloc[0])
'''
a    1
b    2
c    3
Name: e, dtype: int64
'''
 
# iloc索引多行数据
print(df1.iloc[1:])
'''
   a  b  c
1  4  5  6
2  7  8  9
'''
 
# iloc索引多列数据
# 如果如下写法,报错。
print(df1.iloc[:,['a', 'b']])
'''
TypeError: cannot perform reduce with flexible type
'''
# iloc索引多列数据, 正确写法如下:
print(df1.iloc[:,0:2])
'''
   a  b
0  1  2
1  4  5
2  7  8
'''
 
# iloc索引某些行某些列
print(df1.iloc[0:2, 0:1])
'''
   a
0  1
1  4
'''

8.map() applymap() apply()

Series的map方法可以接受一个函数或含有映射关系的字典型对象。使用map是一种实现元素级转换以及其他数据清理工作的便捷方式。(DataFrame中对应的是applymap()函数,当然DataFrame还有apply()函数)

toward_dict = {1: '东', 2: '南', 3: '西', 4: '北'}
df = pd.DataFrame({'house' : list('AABCEFG'),
                   'price' : [100, 90, '', 50, 120, 150, 200],
                   'toward' : ['1','1','2','3','','3','2']})
   house price toward
0     A   100      1
1     A    90      1
2     B            2
3     C    50      3
4     E   120       
5     F   150      3
6     G   200      2


map()方法

df['朝向'] = df.toward.map(toward_dict)
匹配不出来,因为df.toward这列数字是str型的, toward_dict中的key是int,下面修正操作下:两个思路:
   house price toward 朝向
0     A   100      1  NaN
1     A    90      1  NaN
2     B            2  NaN
3     C    50      3  NaN
4     E   120         NaN
5     F   150      3  NaN
6     G   200      2  NaN
#第一种思路:toward_dict的key转换为str型
toward_dict2 = dict((str(key), val) for key, val in toward_dict.items())
# 第二种思路, 将df.toward转为int型
df.toward = df.toward.map(lambda x: np.nan if x == '' else x).map(int,na_action='ignore')
df['朝向2'] = df.toward.map(toward_dict);df

apply()方法

apply()将一个函数作用于DataFrame中的每个行或者列

df = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'],
                   'key2' : ['one', 'two', 'one', 'two', 'one'],
                   'data1' : np.arange(5),
                   'data2' : np.arange(5,10)})
#我们现在用apply来对列data1,data2进行相加
df['total'] = df[['data1','data2']].apply(lambda x : x.sum(),axis=1 )
   key1 key2  data1  data2  total
0    a  one      0      5      5
1    a  two      1      6      7
2    b  one      2      7      9
3    b  two      3      8     11
4    a  one      4      9     13
df.loc['total']=df[['data1','data2']].apply(lambda x : x.sum(),axis=0 )
       key1 key2  data1  data2  total
0        a  one    0.0    5.0    5.0
1        a  two    1.0    6.0    7.0
2        b  one    2.0    7.0    9.0
3        b  two    3.0    8.0   11.0
4        a  one    4.0    9.0   13.0
total  NaN  NaN   10.0   35.0    NaN

applymap()

将函数做用于DataFrame中的所有元素(elements)

例如,在所有元素前面加个字符A

def  addA(x):
    return "A" + str(x)
df.applymap(addA)

        key1  key2  data1  data2  total
0        Aa  Aone   A0.0   A5.0   A5.0
1        Aa  Atwo   A1.0   A6.0   A7.0
2        Ab  Aone   A2.0   A7.0   A9.0
3        Ab  Atwo   A3.0   A8.0  A11.0
4        Aa  Aone   A4.0   A9.0  A13.0
total  Anan  Anan  A10.0  A35.0   Anan

9.chunksize

DataFrame是一个重量级的数据结构,当一个dataframe比较大,占据较大内存的时候,同时又需要对这个dataframe做较复杂或者复杂度非O(1)的操作时,会由于内存占用过大而导致处理速度极速下降。

   对此,我们的方法是尽量避免直接对过大的dataframe直接操作(当然有时候没有办法,必须对整体的dataframe进行操作,这时就需要从其他方面优化,比如尽量较少不必要的列,以降低内存消耗),以从csv文件读取数据为例,可以通过read_csv方法的chunksize参数,设定读取的行数,返回一个固定行数的迭代器,每次读取只消耗相应行数对应的dataframe的内存,从而可以有效的解决内存消耗过多的问题,参考如下demo。

10.set_option

pandas默认打印出来的结果,行和列都有省略,平时还好,打印的内容不会一下子将屏幕占满。但是有时需要查看多列(行)内容时候,这个设置就很烦人了

可以通过set_option()设置display.max_rowsdisplay.max_columns来修改默认打印行列数,

# Input
df = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/Cars93_miss.csv')

# Solution
pd.set_option('display.max_columns', 10)
pd.set_option('display.max_rows', 10)

11.fillna

填充缺失数据

fillna()是最主要的处理方式了。

df1=pd.DataFrame([[1,2,3],[NaN,NaN,2],[NaN,NaN,NaN],[8,8,NaN]])
 	 0 	     1 	     2
0 	1.0 	2.0 	3.0
1 	NaN 	NaN 	2.0
2 	NaN 	NaN 	NaN
3 	8.0 	8.0 	NaN

一.用常数填充
df1.fillna(100)
     0 	     1 	     2
0 	1.0 	2.0 	3.0
1 	100.0 	100.0 	2.0
2 	100.0 	100.0 	100.0
3 	8.0 	8.0 	100.0.通过字典填充不同的常数
df1.fillna({0:10,1:20,2:30})
      0 	 1 	     2
0 	1.0 	2.0 	3.0
1 	10.0 	20.0 	2.0
2 	10.0 	20.0 	30.0
3 	8.0 	8.0 	30.0.传入inplace=True直接修改原对象
df1.fillna(0,inplace=True)
      0 	 1 	     2
0 	1.0 	2.0 	3.0
1 	0.0 	0.0 	2.0
2 	0.0 	0.0 	0.0
3 	8.0 	8.0 	0.0.传入method=“ ”改变差值方式
df2=pd.DataFrame(np.random.randint(0,10,(5,5)))
df2.iloc[1:4,3]=NaN;df2.iloc[2:4,4]=NaN
    0 	1 	2 	 3 	    4
0 	6 	6 	2 	4.0   1.0
1 	4 	7 	0 	NaN   5.0
2 	6 	5 	5 	NaN   NaN
3 	1 	9 	9 	NaN   NaN
4 	4 	8 	1 	5.0   9.0

df2.fillna(method='ffill')#用前面的值来填充
    0 	1 	2 	 3 	  4
0 	6 	6 	2 	4.0  1.0
1 	4 	7 	0 	4.0  5.0
2 	6 	5 	5 	4.0  5.0
3 	1 	9 	9 	4.0  5.0
4 	4 	8 	1 	5.0  9.0.传入limit=“ ”限制填充个数
df2.fillna(method='bfill',limit=2)
    0 	1 	2 	 3 	  4
0 	6 	6 	2 	4.0  1.0
1 	4 	7 	0 	NaN  5.0
2 	6 	5 	5 	5.0  9.0
3 	1 	9 	9 	5.0  9.0
4 	4 	8 	1 	5.0  9.0.传入axis=“ ”修改填充方向
df2.fillna(method="ffill",limit=1,axis=1)
     0 	     1 	     2 	     3 	     4
0 	6.0 	6.0 	2.0 	4.0 	1.0
1 	4.0 	7.0 	0.0 	0.0 	5.0
2 	6.0 	5.0 	5.0 	5.0 	NaN
3 	1.0 	9.0 	9.0 	9.0 	NaN
4 	4.0 	8.0 	1.0 	5.0 	9.0


12.查看数据行列数

pandas返回整个dataframe数据的个数:df.size
pandas返回dataframe行数可能最快的方式:df.shape[0]
pandas返回dataframe列数:df.shape[1] 或者df.columns.size

13、at与iat

at的使用方法与loc类似,但是比loc有更快的访问数据的速度,而且只能访问单个元素,不能访问多个元素。

iat对于iloc的关系就像at对于loc的关系,是一种更快的基于索引位置的选择方法,同at一样只能访问单个元素。

at和iat函数是只能选择某个位置的值,iat是按照行索引和列索引的位置来选取数据的。而at是按照行索引和列索引来选取数据;

 loc和iloc函数的功能包含at和iat函数的功能。
 
 df
   a   b   c
d  0   1   2
e  3   4   5
f  6   7   8
g  9  10  11

#获取第2行,第3列位置的数据
df.iat[1,2]
Out[205]: 5

#获取f行,a列位置的数据
df.at['f','a']
Out[206]: 6

14.ix:

混合索引,同时通过标签和行号选取数据。ix方法也有两个参数,按顺序控制行列选取。

   a   b   c
d  0   1   2
e  3   4   5
f  6   7   8
g  9  10  11

#选取一行
df.ix[1]
Out[201]: 
a    3
b    4
c    5

#错误的混合索引(想选取第一行和e行)
df.ix[[0,'e']]
Out[202]: 
     a    b    c
0  NaN  NaN  NaN
e  3.0  4.0  5.0

#选取区域(e行的前两列)
df.ix['e':,:2]
Out[203]: 
   a   b
e  3   4
f  6   7
g  9  10

15.str.split()

str.split()有三个参数:第一个参数就是引号里的内容:就是分列的依据,可以是空格,符号,字符串等等。
第二个参数就是前面用到的expand=True,这个参数直接将分列后的结果转换成DataFrame。
第三个参数的n=数字就是限制分列的次数。
就是当用于分列的依据符号在有多个的话需要指定分列的次数(不指定的话就会根据符号有几个分列几次)。

import pandas as pd
df=pd.DataFrame({"A":["ad-s","df-w","er-3w","23-wd"],"B":[1,2,3,4]})
df
       A  B
0   ad-s  1
1   df-w  2
2  er-3w  3
3  23-wd  4

df["A"].str.split("-")
0     [ad, s]
1     [df, w]
2    [er, 3w]
3    [23, wd]
.str提供了一个访问series每一行的接口
df["A"].str.split("-")[0]
['ad', 's']
str只是给访问dataframe的列中的内容提供了接口
这里不是访问列,而是访问某列中的每行。访问行可以这样。
df["A"].str.split("-").str[0]
0    ad
1    df
2    er
3    23

# Input
df = pd.DataFrame(["STD, City    State",
"33, Kolkata    West Bengal",
"44, Chennai    Tamil Nadu",
"40, Hyderabad    Telengana",
"80, Bangalore    Karnataka"], columns=['row'])
print(df)
# Solution
df_out = df.row.str.split(',|\t', expand=True)

# Make first row as header
new_header = df_out.iloc[0]
df_out = df_out[1:]
df_out.columns = new_header
print(df_out)

row
0          STD, City    State
1  33, Kolkata    West Bengal
2   44, Chennai    Tamil Nadu
3  40, Hyderabad    Telengana
4  80, Bangalore    Karnataka
================================================
0 STD            City    State
1  33   Kolkata    West Bengal
2  44    Chennai    Tamil Nadu
3  40   Hyderabad    Telengana
4  80   Bangalore    Karnataka


16.聚合方法size()和count()

size跟count的区别: size计数时包含NaN值,而count不包含NaN值

df = pd.DataFrame({"Name":["Alice", "Bob", "Mallory", "Mallory", "Bob" , "Mallory"],
    ...:           "City":["Seattle", "Seattle", "Portland", "Seattle", "Seattle", "Portland"],
    ...:            "Val":[4,3,3,np.nan,np.nan,4]})
    ...: 
    ...: df
    ...: 
Out[10]: 
       City     Name  Val
0   Seattle    Alice  4.0
1   Seattle      Bob  3.0
2  Portland  Mallory  3.0
3   Seattle  Mallory  NaN
4   Seattle      Bob  NaN
5  Portland  Mallory  4.0

count()
df.groupby(["Name", "City"], as_index=False)['Val'].count()

Out[11]: 
      Name      City  Val
0    Alice   Seattle    1
1      Bob   Seattle    1
2  Mallory  Portland    2
3  Mallory   Seattle    0

size()
df.groupby(["Name", "City"])['Val'].size().reset_index(name='Size')

      Name      City  Size
0    Alice   Seattle     1
1      Bob   Seattle     2
2  Mallory  Portland     2
3  Mallory   Seattle     1



分组运算方法 agg()

针对某列使用agg()时进行不同的统计运算

df = pd.DataFrame({'A': list('XYZXYZXYZX'),
                   'B': [1, 2, 1, 3, 1, 2, 3, 3, 1, 2], 
                   'C': [12, 14, 11, 12, 13, 14, 16, 12, 10, 19]})

Out[13]: 
   A  B   C
0  X  1  12
1  Y  2  14
2  Z  1  11
3  X  3  12
4  Y  1  13
5  Z  2  14
6  X  3  16
7  Y  3  12
8  Z  1  10
9  X  2  19

df.groupby('A')['B'].agg({'mean':np.mean, 'standard deviation': np.std})

Out[14]: 
       mean       standard deviation
A                              
X  2.250000            0.957427
Y  2.000000            1.000000
Z  1.333333            0.577350


针对不同的列应用多种不同的统计方法

In [15]: df.groupby('A').agg({'B':[np.mean, 'sum'], 'C':['count',np.std]})

Out[15]: 
          B           C          
     mean    sum   count  std
A                              
X  2.250000   9     4  3.403430
Y  2.000000   6     3  1.000000
Z  1.333333   4     3  2.081666

分组运算方法 apply()

df = pd.DataFrame({'A': list('XYZXYZXYZX'), 
                   'B': [1, 2, 1, 3, 1, 2, 3, 3, 1, 2], 
                   'C': [12, 14, 11, 12, 13, 14, 16, 12, 10, 19]})
Out[16]: 
   A  B   C
0  X  1  12
1  Y  2  14
2  Z  1  11
3  X  3  12
4  Y  1  13
5  Z  2  14
6  X  3  16
7  Y  3  12
8  Z  1  10
9  X  2  19

In [17]: df.groupby('A').apply(np.mean) 
    ...: # 跟下面的方法的运行结果是一致的
    ...: # df.groupby('A').mean()
Out[17]: 
          B          C
A                     
X  2.250000  14.750000
Y  2.000000  13.000000
Z  1.333333  11.666667

apply()方法可以应用lambda函数,举例如下:

In [18]: df.groupby('A').apply(lambda x: x['C']-x['B'])
Out[18]: 
A   
X  0    11
   3     9
   6    13
   9    17
Y  1    12
   4    12
   7     9
Z  2    10
   5    12
   8     9
dtype: int64

In [19]: df.groupby('A').apply(lambda x: (x['C']-x['B']).mean())
Out[19]: 
A
X    12.500000
Y    11.000000
Z    10.333333
dtype: float64


分组运算方法 transform()

前面进行聚合运算的时候,得到的结果是一个以分组名为 index 的结果对象。如果我们想使用原数组的 index 的话,就需要进行 merge 转换。transform(func, *args, **kwargs) 方法简化了这个过程,它会把 func 参数应用到所有分组,然后把结果放置到原数组的 index 上(如果结果是一个标量,就进行广播):

In [20]: df = pd.DataFrame({'group1' :  ['A', 'A', 'A', 'A',
    ...:                                'B', 'B', 'B', 'B'],
    ...:                    'group2' :  ['C', 'C', 'C', 'D',
    ...:                                'E', 'E', 'F', 'F'],
    ...:                    'B'      :  ['one', np.NaN, np.NaN, np.NaN,
    ...:                                 np.NaN, 'two', np.NaN, np.NaN],
    ...:                    'C'      :  [np.NaN, 1, np.NaN, np.NaN,
    ...:                                np.NaN, np.NaN, np.NaN, 4]})           
    ...: df
    ...: 
Out[20]: 
     B    C group1 group2
0  one  NaN      A      C
1  NaN  1.0      A      C
2  NaN  NaN      A      C
3  NaN  NaN      A      D
4  NaN  NaN      B      E
5  two  NaN      B      E
6  NaN  NaN      B      F
7  NaN  4.0      B      F

In [21]: df.groupby(['group1', 'group2'])['B'].transform('count')
Out[21]: 
0    1
1    1
2    1
3    0
4    1
5    1
6    0
7    0
Name: B, dtype: int64

In [22]: df['count_B']=df.groupby(['group1', 'group2'])['B'].transform('count')
    ...: df
    ...: 
Out[22]: 
     B    C group1 group2  count_B
0  one  NaN      A      C        1
1  NaN  1.0      A      C        1
2  NaN  NaN      A      C        1
3  NaN  NaN      A      D        0
4  NaN  NaN      B      E        1
5  two  NaN      B      E        1
6  NaN  NaN      B      F        0
7  NaN  4.0      B      F        0

上面运算的结果分析: {‘group1’:’A’, ‘group2’:’C’}的组合共出现3次,即index为0,1,2。对应”B”列的值分别是”one”,”NaN”,”NaN”,由于count()计数时不包括Nan值,因此{‘group1’:’A’, ‘group2’:’C’}的count计数值为1。
transform()方法会将该计数值在dataframe中所有涉及的rows都显示出来(我理解应该就进行广播)

将某列数据按数据值分成不同范围段进行分组(groupby)运算

np.random.seed(0)
 df = pd.DataFrame({'Age': np.random.randint(20, 70, 100), 
                   'Sex': np.random.choice(['Male', 'Female'], 100), 
                   'number_of_foo': np.random.randint(1, 20, 100)})
    ...: df.head()
    ...: 
Out[23]: 
   Age     Sex      number_of_foo
0   64  Female             14
1   67  Female             14
2   20  Female             12
3   23    Male             17
4   23  Female             15

这里将“Age”列分成三类,有两种方法可以实现:

(a)bins=4
(b)bins=[19, 40, 65, np.inf]
 pd.cut(df['Age'], bins=4)     
 pd.cut(df['Age'], bins=[19,40,65,np.inf])

分组结果范围结果如下:

In [26]: age_groups = pd.cut(df['Age'], bins=[19,40,65,np.inf])
    ...: df.groupby(age_groups).mean()


发布了13 篇原创文章 · 获赞 0 · 访问量 225

猜你喜欢

转载自blog.csdn.net/jaffe507/article/details/105072334