赞
踩
Python Data Analysis Library
pandas是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。Pandas 纳入 了大量库和一些标准的数据模型,提供了高效地操作大型结构化数据集所需的工具。
数据结构是计算机存储、组织数据的方式。 通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关。
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.
通过指定周期和频率,使用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具有以下特点:
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(此前被称为 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
数值型数据的描述性统计主要包括了计算数值型数据的完整情况、最小值、均值、中位 数、最大值、四分位数、极差、标准差、方差、协方差等。在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有两种排序方式,它们分别是按标签与按实际值排序。
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)
在许多情况下,我们将数据分成多个集合,并在每个子集上应用一些函数。在应用函数中,可以执行以下操作 :
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具有功能全面的高性能内存中连接操作,与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
使用“how”参数合并DataFrame:
# 合并两个DataFrame (左连接)
rs = pd.merge(left, right, how='left')
print(rs)
其他合并方法同数据库相同:
合并方法 | 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)
# 合并两个DataFrame (外连接)
rs = pd.merge(left,right,on='subject_id', how='outer')
print(rs)
有如下数据:
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
基本绘图:绘图
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
关键字参数。这些包括 :
bar
或barh
为条形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')
需求如下:
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_rows
和display.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()时进行不同的统计运算
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
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
前面进行聚合运算的时候,得到的结果是一个以分组名为 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都显示出来(我理解应该就进行广播)
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()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。