美文网首页数据分析
[Python] Pandas相关知识

[Python] Pandas相关知识

作者: 半为花间酒 | 来源:发表于2020-05-15 20:29 被阅读0次

内容是以前的学习笔记,内容不全,主观性较大,部分基础知识未展示

0. 魔术方法

显示或隐藏代码,魔术方法内不能含有注释

%%HTML

<script>
code_show=true;
function code_toggle(){
    if (code_show){
    $('div.input').hide();
    } else {
    $('div.input').show();
    }
    code_show = !code_show
}
$( document ).ready(code_toggle);
</script>
<form action="javascript:code_toggle()"><input type="submit" value="点击按钮显示/隐藏文档代码"></form>
%%timeit
# 计时 需要删除注释

1.Series

Series 是个定长的字典序列。

说是定长是因为在存储的时候,相当于两个 ndarray,这也是和字典结构最大的不同。因为在字典的结构里,元素的个数是不固定的。

Series有两个基本属性:index 和 values。

data可以为list、numpy.array或者dict

import pandas as pd
import numpy as np
# 构建序列
# Series
s = pd.Series([1,3,6,np.nan,44,1]) # 矩阵中加入空值
print(s)
# 默认index从0开始,如果想要按照自己的索引设置,则修改index参数,如:index=[3,4,3,7,8,9]
# np.nan类型是float64
import pandas as pd
from pandas import Series, DataFrame # 注意大写

x1 = Series([1,2,3,4])
x2 = Series(data=[1,2,3,4], index=['a', 'b', 'c', 'd'])

print (x1)
print (x2)

# 采用字典的方式来创建 Series,键变为行索引
d = {'a':1, 'b':2, 'c':3, 'd':4}
x3 = Series(d,name = '这是一个序列')
print (x3)
x3[['a','b']] = [33,4] # 修改
print(type(x3))

# 类似字典的操作:in和get()
'c' in x1 # 判断'c'是否在索引中,
x1.get('c',60) # 从x1中搜索索引c的值,如果存在则取出,不存在则返回60

# 索引修改
x2 = x1.copy() # pandas里用copy则为深拷贝
x2.index = ['h','i','j']
# Series相关方法
x3.values
50 in x3.values # 返回bool

x3.index
x3.index.name = 'index_name'
x3.column.name = 'column_name' # 给索引设置名字
x3.dtype

2.DataFrame

2.1 DataFrame的简单运用

# DataFrame
dates = pd.date_range('2018-08-19',periods=6)
# dates = pd.date_range('2018-08-19','2018-08-24') 
# 起始、结束  与上述等价
'''
numpy.random.randn(d0, d1, …, dn)是从标准正态分布中返回一个或多个样本值。
numpy.random.rand(d0, d1, …, dn)的随机样本位于[0, 1)中。
(6,4)表示6行4列数据
'''
df = pd.DataFrame(np.random.randn(6,4),index=dates,columns=['a','b','c','d'])
print(df)
# DataFrame既有行索引也有列索引, 它可以被看做由Series组成的大字典。
# 重命名列名 columns,行名 index,以字典的形式

df2.rename(columns={'Chinese': 'YuWen', 'English': 'Yingyu'}, inplace = True)
df2.rename(index={'ZhangFei': 'MangFu'}, inplace = True) # 写明 inplace = True,原基础上修改

print(df2)
# DataFrame 相关方法

df.shape # 行 列 构成tuple
df.size # 总个数
df.ndim # 维度
df.dtypes # 数据类型
df.columns.tolist() # 获取列标签强转list
df.index.tolist()
print(df['b']) # 选择列
# 也可以用df.b
# 未指定行标签和列标签的数据
df1 = pd.DataFrame(np.arange(12).reshape(3,4))
print(df1)
# 另一种方式
df2 = pd.DataFrame({
    'A': [1,2,3,4],
    'B': pd.Timestamp('20180819'),   # 时间戳
    'C': pd.Series([1,6,9,10],dtype='float32'),
    'D': np.array([3] * 4,dtype='int32'),
    'E': pd.Categorical(['test','train','test','train']),
    'F': 'foo'
})
print(df2)
print(df2.index)
print(df2.columns)
print(df2.values) # 返回矩阵的所有值

df2.info() # 查看各列类型
   A          B     C  D      E    F
0  1 2018-08-19   1.0  3   test  foo
1  2 2018-08-19   6.0  3  train  foo
2  3 2018-08-19   9.0  3   test  foo
3  4 2018-08-19  10.0  3  train  foo

RangeIndex(start=0, stop=4, step=1)

Index(['A', 'B', 'C', 'D', 'E', 'F'], dtype='object')

[[1 Timestamp('2018-08-19 00:00:00') 1.0 3 'test' 'foo']
 [2 Timestamp('2018-08-19 00:00:00') 6.0 3 'train' 'foo']
 [3 Timestamp('2018-08-19 00:00:00') 9.0 3 'test' 'foo']
 [4 Timestamp('2018-08-19 00:00:00') 10.0 3 'train' 'foo']]
# 数据统计学总结
print(df2.describe())
              A          C    D
count  4.000000   4.000000  4.0
mean   2.500000   6.500000  3.0
std    1.290994   4.041452  0.0
min    1.000000   1.000000  3.0
25%    1.750000   4.750000  3.0
50%    2.500000   7.500000  3.0
75%    3.250000   9.250000  3.0
max    4.000000  10.000000  3.0
# 平均值
df.mean() # axis=0
df.mean(1) # axis=1

#其他统计函数
df.median() # 中位数
df.var() # 方差
df['Chinese'].idxmax() # 返回指定列最大值的索引,最小值 idxmin()
# 行列转置
print(df2.T)
# print(np.transpose(df2))等价于上述操作
'''
axis=1表示行
axis=0表示列
默认ascending(升序)为True
ascending=True表示升序,ascending=False表示降序
下面两行分别表示按行升序与按行降序
'''
print(df2.sort_index(axis=1,ascending=True))
   A          B     C  D      E    F
0  1 2018-08-19   1.0  3   test  foo
1  2 2018-08-19   6.0  3  train  foo
2  3 2018-08-19   9.0  3   test  foo
3  4 2018-08-19  10.0  3  train  foo
print(df2.sort_index(axis=1,ascending=False)) # axis=1列索引降序排序
     F      E  D     C          B  A
0  foo   test  3   1.0 2018-08-19  1
1  foo  train  3   6.0 2018-08-19  2
2  foo   test  3   9.0 2018-08-19  3
3  foo  train  3  10.0 2018-08-19  4
# 表示按列降序与按列升序
print(df2.sort_index(axis=0,ascending=False)) # axis=0行索引降序排序
   A          B     C  D      E    F
3  4 2018-08-19  10.0  3  train  foo
2  3 2018-08-19   9.0  3   test  foo
1  2 2018-08-19   6.0  3  train  foo
0  1 2018-08-19   1.0  3   test  foo
print(df2.sort_index(axis=0,ascending=True)) # axis=1则为列索引排序
   A          B     C  D      E    F
0  1 2018-08-19   1.0  3   test  foo
1  2 2018-08-19   6.0  3  train  foo
2  3 2018-08-19   9.0  3   test  foo
3  4 2018-08-19  10.0  3  train  foo

对特定列数值排列

# 表示对C列降序排列
print(df2.sort_values(by='C',ascending=False))

频数统计

s = pd.Series(np.random.randint(0, 7, size=10)) # size指定索引长度

s.value_counts()  
# 降序,同时所需要的树变成索引,可用.index[0]提取众数

datetime(), timedelta()

# 转换为 时间戳格式 datetime()
df['考试时间'] = pd.to_datetime(df['考试时间'],format = '%Y%m%d',errors = 'coerce') 
# 设置格式,并且防止报错,不符合格式的转换为缺失值

# 转换为时间戳格式后可以使用相关方法
df['考试时间'].dt.year # month day

# 时间差数据 timedelta() 被减数为现在的时间
df['diff_day'] = pd.datetime.now()-df['考试时间']
df['diff_day'].dt.days.tolist() # datetime()格式用的是 day
df['时间差'] = df['diff_day']/pd.Timedelta('1 D') # 1 H 或 1 M也可以转换
df['时间差'].round(decimals=0) #  保留0个有效数字  为四舍五入转
# 转换为整型天数的另一种方法  为截断转
df['diff_day'].astype('timedelta64[D]')
df['考试时间'].str.split('-')[0] # 表示取第一行
df['考试时间'].str.split('-').str[0] # 表示所有元素取第一个

3.pandas选择数据

3.1 实战筛选

import pandas as pd
import numpy as np
dates = pd.date_range('20180819', periods=6)
df = pd.DataFrame(np.arange(24).reshape((6,4)),index=dates, columns=['A','B','C','D'])
print(df)
# 选择跨越多行或多列
# 选取前3行
print(df[0:3])
            A  B   C   D
2018-08-19  0  1   2   3
2018-08-20  4  5   6   7
2018-08-21  8  9  10  11
print(df['2018-08-19':'2018-08-21'])
            A  B   C   D
2018-08-19  0  1   2   3
2018-08-20  4  5   6   7
2018-08-21  8  9  10  11
# 根据标签选择数据
# 获取特定行或列
# 指定行数据
print(df.loc['20180819'])  
A    0
B    1
C    2
D    3
Name: 2018-08-19 00:00:00, dtype: int32
# 指定列
# 两种方式
print(df.loc[:,'A':'B']) # 选择相邻列
print(df.loc[:,['A','B']]) # 选择指定多列
             A   B
2018-08-19   0   1
2018-08-20   4   5
2018-08-21   8   9
2018-08-22  12  13
2018-08-23  16  17
2018-08-24  20  21
# 行与列同时检索
print(df.loc['20180819',['A','B']])
A    0
B    1
Name: 2018-08-19 00:00:00, dtype: int32
# 根据序列iloc
# 获取特定位置的值
print(df.iloc[3,1]) # iloc中的数字是python中的位置不是绝对数字

# 等价于df.iat[3,1]
print(df.iloc[3:5,1:3]) # 不包含末尾5或3,同列表切片
             B   C
2018-08-22  13  14
2018-08-23  17  18
# 跨行操作
print(df.iloc[[1,3,5],1:3])
# 混合选择
# print(df.ix[:3,['A','C']]) # 同时用位置索引和名字,但ix[]已经被废除
print(df.iloc[:3,[0,2]]) # 结果同上
            A   C
2018-08-19  0   2
2018-08-20  4   6
2018-08-21  8  10    
# 通过判断的筛选
print(df[df.A>8]) # df.A>8返回矩阵的bool值,作为内嵌套可以选出特定行
print(df.loc[df.A>8]) # 也可以用loc()
             A   B   C   D
2018-08-22  12  13  14  15
2018-08-23  16  17  18  19
2018-08-24  20  21  22  23
# 多个条件用()分隔开,&且 |或
df2.loc[(df2.Chinese > 90)|(df2.Math > 90),['English']]

between(), isin()

# between()只能数值型
df2[df2['E'].isin(['two', 'four'])]
df['语文'].isin(['95','90']) # 需用list形式写(含单个)

df['语文'].between(90,98,inclusive=True) # 返回布尔值
  • 3.2 筛选总结

1.ilocix区别

总结:相同点:iloc可以取相应的值,操作方便,与ix操作类似。

不同点:ix可以混合选择,可以填入column对应的字符选择,而iloc只能采用index索引,对于列数较多情况下,ix要方便操作许多。

2.lociloc区别

总结:相同点:都可以索引处块数据

不同点:iloc可以检索对应值,两者操作不同。

3.ixlociloc三者的区别

n总结:ix是混合loc与iloc操作

如下:对比三者操作,输出结果相同

print(df.loc['20180819','A':'B'])
print(df.iloc[0,0:2])
print(df.ix[0,'A':'B'])
A    0
B    1
Name: 2018-08-19 00:00:00, dtype: int32

3.2 删除数据

# 删除指定列
df2 = df.drop(columns=['Chinese'])
# del df['Chinese']  # 只能删除一个
# df2 = df.drop(labels = ['Chinese'],axis = 1) #三者等同


# 删除指定行
df2 = df2.drop(index=2)
df2 = df2.drop([1,7]) # 删除多行
# df2 = df2.drop(labels = 2,axis=0) # 默认axis = 0 跨行/行索引

3.3 改、查数据

df2['Math'] = np.where((df2['Math'].astype(np.int64))<60,'low','high')
df2
# 移动列
# 将 Math 移至第一列
Math = df2['Math']
del df2['Math']

# DataFrame.insert(位置,列标签.数据)
df2.insert(0,'Math',Math)

df[~(df['语文']>=90)] # ~+()表示取反


# 包含某个字符串
data.loc[(data.smallRNAName.str.contains('mmu-miR-'))]

4.Pandas设置值

4.1 创建数据

对数值进行移动

s = pd.Series([1,3,5,np.nan,6,8], index=dates).shift()  # 数值向下移动一位

4.2 根据位置设置loc和iloc

dates = pd.date_range('20180820',periods=6)
df = pd.DataFrame(np.arange(24).reshape(6,4), index=dates, columns=['A','B','C','D'])
# 根据位置设置loc和iloc,直接赋值
df.iloc[2,2] = 111
df.loc['20180820','B'] = 2222
print(df)
             A     B    C   D
2018-08-20   0  2222    2   3
2018-08-21   4     5    6   7
2018-08-22   8     9  111  11
2018-08-23  12    13   14  15
2018-08-24  16    17   18  19
2018-08-25  20    21   22  23

4.3 根据条件设置

# 根据条件设置
# 更改B中的数,而更改的位置取决于4的位置,并设相应位置的数为0
df.B[df.A>4] = 0
print(df)
             A     B    C   D
2018-08-20   0  2222    2   3
2018-08-21   4     5    6   7
2018-08-22   8     0  111  11
2018-08-23  12     0   14  15
2018-08-24  16     0   18  19
2018-08-25  20     0   22  23
df.B.loc[df.A>4] = 0
print(df)
             A     B    C   D
2018-08-20   0  2222    2   3
2018-08-21   4     5    6   7
2018-08-22   8     0  111  11
2018-08-23  12     0   14  15
2018-08-24  16     0   18  19
2018-08-25  20     0   22  23

4.4 按行或列设置

# 按行或列设置,整列全部设置
# 列批处理,F列全改为NaN
df['F'] = np.nan
print(df)
             A     B    C   D   F
2018-08-20   0  2222    2   3 NaN
2018-08-21   4     5    6   7 NaN
2018-08-22   8     0  111  11 NaN
2018-08-23  12     0   14  15 NaN
2018-08-24  16     0   18  19 NaN
2018-08-25  20     0   22  23 NaN

4.5 添加Series序列(长度必须对齐)

# 矩阵中添加一列
df['E'] = pd.Series([1,2,3,4,5,6], index=pd.date_range('20180820',periods=6))
print(df) 
             A     B    C   D   F  E
2018-08-20   0  2222    2   3 NaN  1
2018-08-21   4     5    6   7 NaN  2
2018-08-22   8     0  111  11 NaN  3
2018-08-23  12     0   14  15 NaN  4
2018-08-24  16     0   18  19 NaN  5
2018-08-25  20     0   22  23 NaN  6

4.6 设定某行某列为特定值

# 设定某行某列为特定值
df.loc['20180820','A'] = 56
# df.iloc[0,0] = 56 方法同上,矩阵中设置值
print(df)

# 查找和赋值结合
body.loc[body['影响因子'].astype(np.float)>4,'影响因子'] = 'high'
             A     B    C   D   F  E
2018-08-20  56  2222    2   3 NaN  1
2018-08-21   4     5    6   7 NaN  2
2018-08-22   8     0  111  11 NaN  3
2018-08-23  12     0   14  15 NaN  4
2018-08-24  16     0   18  19 NaN  5
2018-08-25  20     0   22  23 NaN  6

4.7 修改一整行数据

# 修改一整行数据
df.iloc[1] = np.nan # df.iloc[1,:]=np.nan
print(df)

# 按行统计
miRNA_data.loc[~((miRNA_data == 0).sum(axis=1)>=4)]
               A       B      C     D   F    E
2018-08-20  76.0  2222.0    2.0   3.0 NaN  1.0
2018-08-21   NaN     NaN    NaN   NaN NaN  NaN
2018-08-22   8.0     0.0  111.0  11.0 NaN  3.0
2018-08-23  12.0     0.0   14.0  15.0 NaN  4.0
2018-08-24  16.0     0.0   18.0  19.0 NaN  5.0
2018-08-25  20.0     0.0   22.0  23.0 NaN  6.0
df.loc['20180820'] = np.nan # df.loc['20180820',]=np.nan
df.iloc[1] = np.nan # df.iloc[1,:]=np.nan  # 4种方法一样
print(df)
               A    B      C     D   F    E
2018-08-20   NaN  NaN    NaN   NaN NaN  NaN
2018-08-21   NaN  NaN    NaN   NaN NaN  NaN
2018-08-22   8.0  0.0  111.0  11.0 NaN  3.0
2018-08-23  12.0  0.0   14.0  15.0 NaN  4.0
2018-08-24  16.0  0.0   18.0  19.0 NaN  5.0
2018-08-25  20.0  0.0   22.0  23.0 NaN  6.0

在pandas中,用np.nan来代表缺失值,这些值默认不会参与运算。

reindex()允许修改、增加、删除指定轴上的索引,并返回一个数据副本。

df1 = df.reindex(index=dates[0:4], columns=list(df.columns)+['E'])
df1.loc[dates[0]:dates[1],'E'] = 1

5.Pandas处理丢失数据+重复数据

5.1 创建含NaN的矩阵

# Pandas处理丢失数据
import pandas as pd
import numpy as np
# 创建含NaN的矩阵
# 如何填充和删除NaN数据?
dates = pd.date_range('20180820',periods=6)
df = pd.DataFrame(np.arange(24).reshape((6,4)),index=dates,columns=['A','B','C','D']) 
# a.reshape(6,4)等价于a.reshape((6,4))
# 设置缺失值
df.iloc[0,1] = np.nan # 缺失值是浮点型
df.iloc[1,2] = np.nan
print(df)
             A     B     C   D
2018-08-20   0   NaN   2.0   3
2018-08-21   4   5.0   NaN   7
2018-08-22   8   9.0  10.0  11
2018-08-23  12  13.0  14.0  15
2018-08-24  16  17.0  18.0  19
2018-08-25  20  21.0  22.0  23

5.2 删除掉有NaN的行或列

# 删除掉有NaN的行或列
print(df.dropna()) # 默认是删除掉含有NaN的行
             A     B     C   D
2018-08-22   8   9.0  10.0  11
2018-08-23  12  13.0  14.0  15
2018-08-24  16  17.0  18.0  19
2018-08-25  20  21.0  22.0  23
print(df.dropna(
    axis=0, # 0对行进行操作;1对列进行操作
    how='any' # 'any':只要存在NaN就drop掉;'all':必须全部是NaN才drop
))

titanic.dropna(how='any',subset=['Cabin'],axis=0) # 可限定缺失值存在的列

# 可以找出某列含有nan的行
# 然后全部赋予np.nan
# 最后使用df.dropna(how='all')
             A     B     C   D
2018-08-22   8   9.0  10.0  11
2018-08-23  12  13.0  14.0  15
2018-08-24  16  17.0  18.0  19
2018-08-25  20  21.0  22.0  23
# 删除掉所有含有NaN的列
print(df.dropna(
    axis=1,
    how='any'
))
             A   D
2018-08-20   0   3
2018-08-21   4   7
2018-08-22   8  11
2018-08-23  12  15
2018-08-24  16  19
2018-08-25  20  23

5.3 替换NaN值为0或者其他

# 评估各列缺失值情况
titanic.apply(lambda x:sum(x.isnull())/len(x),axis=0)

# 替换NaN值为0或者其他
print(df.fillna(value=0))

df = df.fillna(df.mean()) # 替换为该列均值

titanic.replace([np.inf, -np.inf], np.nan) # 将无限值转为缺失值

# 分类变量用众数进行替换
titanic['Cabin'].fillna(titanic['Cabin'].mode()[0],inplace=True) # fillna()可以用values={'':''}进行多列各自缺失值替换,值可以用函数

titanic['Embarked'].fillna(method='ffill') # 前向填充缺失值
titanic['Embarked'].fillna(method='bfill') # 后向填充缺失值

5.4 是否有缺失数据NaN

# 是否有缺失数据NaN
# 是否为空
print(df.isnull())
print(df.isna())
                A      B      C      D
2018-08-20  False   True  False  False
2018-08-21  False  False   True  False
2018-08-22  False  False  False  False
2018-08-23  False  False  False  False
2018-08-24  False  False  False  False
2018-08-25  False  False  False  False
# 检测某列是否有缺失数据NaN
print(df.isnull().any())
A    False
B     True
C     True
D    False
dtype: bool
# 检测数据中是否存在NaN,如果存在就返回True
print(np.any(df.isnull()))
True

5.5 去重

any(titanic.duplicated())
df2 = df2.drop_duplicates() # 去除重复行
# 以下二者等同
df2 = df2.drop_duplicates('Math',keep='first') # 去除特定列的重复行
df2 = df2.drop_duplicates(subset=['Math'])

# keep='first'表示保留第一次出现的重复行,是默认值。
# keep另外两个取值为last和False,分别表示保留最后一次出现的重复行和去除所有重复行。

5.6 处理异常值

# 用均数 标准差判断
age_bar = titanic['Age'].mean()
age_std = titanic['Age'].std()
titanic[titanic['Age']> age_bar + 2.5*age_std]

# 用四分位数 分位差判断
Q1 = titanic['Age'].quantile(q=0.25)
Q3 = titanic['Age'].quantile(q=0.75)
IQR = Q3 - Q1 #分位差
any(titanic['Age'] > Q3 + 1.5 * IQR)
# 图形法直观显示
import matplotlib.pyplot as plt
titanic['Age'].plot(kind='box')
plt.style.use('seaborn') # 美化
titanic.Age.plot(kind='hist',bins=30,density=True) # bins 柱个数,density 频率
titanic.Age.plot(kind='kde') # 核密度估计曲线
plt.show()

5.7 分类

df = pd.DataFrame({"id":[1,2,3,4,5,6], "raw_grade":['a', 'b', 'b', 'a', 'e', 'e']})

# 把raw_grade转换为分类类型
df["grade"] = df["raw_grade"].astype("category")
# 重命名类别名为更有意义的名称
df["grade"].cat.categories = ["very good", "good", "very bad"]
# 对分类重新排序,并添加缺失的分类
df["grade"] = df["grade"].cat.set_categories(["very bad", "bad", "medium", "good", "very good"])
# 排序是按照分类的顺序进行的,而不是字典序
df.sort_values(by="grade")
# 按分类分组时,也会显示空的分类
df.groupby("grade").size()

6.Pandas导入导出

6.1 导入数据

import pandas as pd # 加载模块
# 读取csv
data = pd.read_csv('student.csv', encoding = 'utf-8')

# 默认utf-8
body = pd.read_csv('practice.csv',
                   header=0, # 默认0将第一行设为表头,不用表头则设置为None
                   index_col=['name','age'], # 默认None,可以自定义
                   names=['a','b','c','d'], # 自定义表头
                   usecols=[0,1,2,3], # 读取指定列
                   nrows=3, # 读取前3行
                   skiprows=2, # 跳过前两行, [2,3,4] 跳过2-4行,绝对数字
                   skipfooter=2, # 跳过最后两行,须配合engine
                   engine='python', # C更快,python更完善
                   encoding = 'utf-8',
                   na_values=['male'], # 自定义缺失值的默认值
                   keep_default_na=True, # 默认为True
                   dtype = str) # 全部数据转为str
titanic = pd.read_csv('Titanic.csv',encoding = 'utf-8',na_values='')  # 把空值或其他值作为缺失值
# 指定索引列
index_col = 'user_id'
# 重写列名
names = ['user_id','book_id']

# 只获取前10行
body = pd.read_csv('practice.csv',nrow = 10)

# 读取excel文件要考虑sheet页
df = pd.read_excel('practice.xlsx',encoding = 'utf-8',sheet_name = u'杂志选刊')
# df = pd.read_excel('practice.xlsx',encoding = 'utf-8',sheet_name = 0) 同上,第一个工作页
# 也可以用xlrd
file = pd.ExcelFile('student.xlsx')
df = file.parse('student_sheet') # 选工作页

# 导出
body.to_csv('test.csv',
            encoding='utf-8',
            index=False,
            header=False) # 不导出列索引 
# 前三行
print(data.head(3))
# 后三行
print(data.tail(3))
   Student ID  name   age  gender
0        1100  Kelly   22  Female
1        1101    Clo   21  Female
2        1102  Tilly   22  Female

    Student ID name   age  gender
11        1111    Dw    3  Female
12        1112     Q   23    Male
13        1113     W   21  Female

6.2 导出数据

# 将资料存取成pickle
data.to_pickle('student.pickle')

# 保存excel
body.to_excel('test.xlsx',encoding='utf-8',index=False,sheet_name = 'one')

7.Pandas合并操作

7.1 Pandas合并concat

import pandas as pd
import numpy as np

# 定义资料集
df1 = pd.DataFrame(np.ones((3,4))*0, columns=['a','b','c','d'])
df2 = pd.DataFrame(np.ones((3,4))*1, columns=['a','b','c','d'])
df3 = pd.DataFrame(np.ones((3,4))*2, columns=['a','b','c','d'])
# concat纵向合并,axis=1为横向拼接,索引为并集
res = pd.concat([df1,df2,df3],axis=0)

# 打印结果
print(res)
     a    b    c    d
0  0.0  0.0  0.0  0.0
1  0.0  0.0  0.0  0.0
2  0.0  0.0  0.0  0.0
0  1.0  1.0  1.0  1.0
1  1.0  1.0  1.0  1.0
2  1.0  1.0  1.0  1.0
0  2.0  2.0  2.0  2.0
1  2.0  2.0  2.0  2.0
2  2.0  2.0  2.0  2.0
# 上述合并过程中,index重复,下面给出重置index方法
# 只需要将index_ignore设定为True即可
res = pd.concat([df1,df2,df3],axis=0,ignore_index=True)

# 打印结果
print(res)
     a    b    c    d
0  0.0  0.0  0.0  0.0
1  0.0  0.0  0.0  0.0
2  0.0  0.0  0.0  0.0
3  1.0  1.0  1.0  1.0
4  1.0  1.0  1.0  1.0
5  1.0  1.0  1.0  1.0
6  2.0  2.0  2.0  2.0
7  2.0  2.0  2.0  2.0
8  2.0  2.0  2.0  2.0
# join 合并方式
#定义资料集
df1 = pd.DataFrame(np.ones((3,4))*0, columns=['a','b','c','d'], index=[1,2,3])
df2 = pd.DataFrame(np.ones((3,4))*1, columns=['b','c','d','e'], index=[2,3,4])
,ignore_index=True'''
join='outer',函数默认为join='outer'。此方法是依照column来做纵向合并,有相同的column上下合并在一起,并集
其他独自的column各自成列,原来没有值的位置皆为NaN填充。
'''
# 纵向"外"合并df1与df2
res = pd.concat([df1,df2],axis=0,join='outer',ignore_index=True)

print(res)
     a    b    c    d    e
0  0.0  0.0  0.0  0.0  NaN
1  0.0  0.0  0.0  0.0  NaN
2  0.0  0.0  0.0  0.0  NaN
3  NaN  1.0  1.0  1.0  1.0
4  NaN  1.0  1.0  1.0  1.0
5  NaN  1.0  1.0  1.0  1.0
# join='inner'合并相同的字段,交集
# 纵向"内"合并df1与df2
res = pd.concat([df1,df2],axis=0,join='inner')
# 打印结果
print(res)
     b    c    d
1  0.0  0.0  0.0
2  0.0  0.0  0.0
3  0.0  0.0  0.0
2  1.0  1.0  1.0
3  1.0  1.0  1.0
4  1.0  1.0  1.0
# join_axes(依照axes合并)
#定义资料集
df1 = pd.DataFrame(np.ones((3,4))*0, columns=['a','b','c','d'], index=[1,2,3])
df2 = pd.DataFrame(np.ones((3,4))*1, columns=['b','c','d','e'], index=[2,3,4])
print(df1)
# 依照df1.index进行横向合并
res = pd.concat([df1,df2],axis=1,join_axes=[df1.index])
print(res)
     a    b    c    d    b    c    d    e
1  0.0  0.0  0.0  0.0  NaN  NaN  NaN  NaN
2  0.0  0.0  0.0  0.0  1.0  1.0  1.0  1.0
3  0.0  0.0  0.0  0.0  1.0  1.0  1.0  1.0
# 移除join_axes参数,打印结果
res = pd.concat([df1,df2],axis=1)
print(res)
     a    b    c    d    b    c    d    e
1  0.0  0.0  0.0  0.0  NaN  NaN  NaN  NaN
2  0.0  0.0  0.0  0.0  1.0  1.0  1.0  1.0
3  0.0  0.0  0.0  0.0  1.0  1.0  1.0  1.0
4  NaN  NaN  NaN  NaN  1.0  1.0  1.0  1.0
# append(添加数据)
# append只有纵向合并,没有横向合并
#定义资料集
df1 = pd.DataFrame(np.ones((3,4))*0, columns=['a','b','c','d'])
df2 = pd.DataFrame(np.ones((3,4))*1, columns=['a','b','c','d'])
df3 = pd.DataFrame(np.ones((3,4))*2, columns=['a','b','c','d'])
s1 = pd.Series([1,2,3,4], index=['a','b','c','d'])
# 将df2合并到df1下面,以及重置index,并打印出结果
res = df1.append(df2,ignore_index=True)
print(res)
     a    b    c    d
0  0.0  0.0  0.0  0.0
1  0.0  0.0  0.0  0.0
2  0.0  0.0  0.0  0.0
3  1.0  1.0  1.0  1.0
4  1.0  1.0  1.0  1.0
5  1.0  1.0  1.0  1.0
# 合并多个df,将df2与df3合并至df1的下面,以及重置index,并打印出结果
res = df1.append([df2,df3], ignore_index=True)
print(res)
     a    b    c    d
0  0.0  0.0  0.0  0.0
1  0.0  0.0  0.0  0.0
2  0.0  0.0  0.0  0.0
3  1.0  1.0  1.0  1.0
4  1.0  1.0  1.0  1.0
5  1.0  1.0  1.0  1.0
6  2.0  2.0  2.0  2.0
7  2.0  2.0  2.0  2.0
8  2.0  2.0  2.0  2.0
# 合并series,将s1合并至df1,以及重置index,并打印结果
res = df1.append(s1,ignore_index=True)
print(res)
     a    b    c    d
0  0.0  0.0  0.0  0.0
1  0.0  0.0  0.0  0.0
2  0.0  0.0  0.0  0.0
3  1.0  2.0  3.0  4.0
# 总结:两种常用纵向合并方式
res = pd.concat([df1, df2, df3], axis=0, ignore_index=True)
res1 = df1.append([df2, df3], ignore_index=True)

7.2.Pandas 合并 merge

7.2.1 定义资料集并打印出

import pandas as pd
# 依据一组key合并
# 定义资料集并打印出
left = pd.DataFrame({'key' : ['K0','K1','K2','K3'],
                     'A' : ['A0','A1','A2','A3'],
                     'B' : ['B0','B1','B2','B3']})

right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
                      'C' : ['C0', 'C1', 'C2', 'C3'],
                      'D' : ['D0', 'D1', 'D2', 'D3']})
print(left)
print(right)
    A   B key
0  A0  B0  K0
1  A1  B1  K1
2  A2  B2  K2
3  A3  B3  K3

    C   D key
0  C0  D0  K0
1  C1  D1  K1
2  C2  D2  K2
3  C3  D3  K3

7.2.2 依据key column合并,并打印

# 依据key column合并,并打印
res = pd.merge(left,right,on='key')
print(res)
    A   B key   C   D
0  A0  B0  K0  C0  D0
1  A1  B1  K1  C1  D1
2  A2  B2  K2  C2  D2
3  A3  B3  K3  C3  D3
#  依据两组key合并
#定义资料集并打印出
left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
                      'key2': ['K0', 'K1', 'K0', 'K1'],
                      'A': ['A0', 'A1', 'A2', 'A3'],
                      'B': ['B0', 'B1', 'B2', 'B3']})
right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
                       'key2': ['K0', 'K0', 'K0', 'K0'],
                       'C': ['C0', 'C1', 'C2', 'C3'],
                       'D': ['D0', 'D1', 'D2', 'D3']})
print(left)
print(right)
    A   B key1 key2
0  A0  B0   K0   K0
1  A1  B1   K0   K1
2  A2  B2   K1   K0
3  A3  B3   K2   K1

    C   D key1 key2
0  C0  D0   K0   K0
1  C1  D1   K0   K1
2  C2  D2   K1   K0
3  C3  D3   K2   K1

7.2.3 两列合并

# 依据key1与key2 columns进行合并,并打印出四种结果['left', 'right', 'outer', 'inner']
res = pd.merge(left, right, on=['key1', 'key2'], how='inner')
print(res)
    A   B key1 key2   C   D
0  A0  B0   K0   K0  C0  D0
1  A2  B2   K1   K0  C1  D1
2  A2  B2   K1   K0  C2  D2
res = pd.merge(left, right, on=['key1', 'key2'], how='outer') # on内可以交换位置做笛卡尔积
print(res)
     A    B key1 key2    C    D
0   A0   B0   K0   K0   C0   D0
1   A1   B1   K0   K1  NaN  NaN
2   A2   B2   K1   K0   C1   D1
3   A2   B2   K1   K0   C2   D2
4   A3   B3   K2   K1  NaN  NaN
5  NaN  NaN   K2   K0   C3   D3
res = pd.merge(left, right, on=['key1', 'key2'], how='left')
print(res)
# 也可以用left_on right_on
    A   B key1 key2    C    D
0  A0  B0   K0   K0   C0   D0
1  A1  B1   K0   K1  NaN  NaN
2  A2  B2   K1   K0   C1   D1
3  A2  B2   K1   K0   C2   D2
4  A3  B3   K2   K1  NaN  NaN
res = pd.merge(left, right, on=['key1', 'key2'], how='right')
print(res)
     A    B key1 key2   C   D
0   A0   B0   K0   K0  C0  D0
1   A2   B2   K1   K0  C1  D1
2   A2   B2   K1   K0  C2  D2
3  NaN  NaN   K2   K0  C3  D3

7.2.4 Indicator设置合并列名称

# Indicator
df1 = pd.DataFrame({'col1':[0,1],'col_left':['a','b']})
df2 = pd.DataFrame({'col1':[1,2,2],'col_right':[2,2,2]})
print(df1)
   col1 col_left
0     0        a
1     1        b
print(df2)
   col1  col_right
0     1          2
1     2          2
2     2          2
# 依据col1进行合并,并启用indicator=True,最后打印
res = pd.merge(df1,df2,on='col1',how='outer',indicator=True) # 分析合并列
print(res)
   col1 col_left  col_right      _merge
0     0        a        NaN   left_only
1     1        b        2.0        both
2     2      NaN        2.0  right_only
3     2      NaN        2.0  right_only
# 自定义indicator column的名称,并打印出
res = pd.merge(df1,df2,on='col1',how='outer',indicator='indicator_column')
print(res)
   col1 col_left  col_right indicator_column
0     0        a        NaN        left_only
1     1        b        2.0             both
2     2      NaN        2.0       right_only
3     2      NaN        2.0       right_only

7.2.5 依据index合并

# 依据index合并
#定义资料集并打印出
left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
                     'B': ['B0', 'B1', 'B2']},
                     index=['K0', 'K1', 'K2'])
right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],
                      'D': ['D0', 'D2', 'D3']},
                     index=['K0', 'K2', 'K3'])
# 依据左右资料集的index进行合并,how='outer',并打印
res = pd.merge(left,right,left_index=True,right_index=True,how='outer')
print(res)
      A    B    C    D
K0   A0   B0   C0   D0
K1   A1   B1  NaN  NaN
K2   A2   B2   C2   D2
K3  NaN  NaN   C3   D3
# 依据左右资料集的index进行合并,how='inner',并打印
res = pd.merge(left,right,left_index=True,right_index=True,how='inner')
print(res)
     A   B   C   D
K0  A0  B0  C0  D0
K2  A2  B2  C2  D2

7.2.6 解决overlapping的问题

# 解决overlapping的问题
#定义资料集
boys = pd.DataFrame({'k': ['K0', 'K1', 'K2'], 'age': [1, 2, 3]})
girls = pd.DataFrame({'k': ['K0', 'K0', 'K3'], 'age': [4, 5, 6]})
print(boys)
   age   k
0    1  K0
1    2  K1
2    3  K2
print(girls)
   age   k
0    4  K0
1    5  K0
2    6  K3
# 使用suffixes解决overlapping的问题,即有相同名字列但意义不同都要保留
# 比如将上面两个合并时,age重复了,则可通过suffixes设置,以此保证不重复,不同名
res = pd.merge(boys,girls,on='k',suffixes=['_boy','_girl'],how='inner')
print(res)
   age_boy   k  age_girl
0        1  K0         4
1        1  K0         5

8. Pandas高级操作

apply()

df.apply(lambda x:x.max()-x.min())

def plus(df,n,m):
    df['new1'] = (df['Chinese']+df['English']) * m
    df['new2'] = (df['Chinese']+df['English']) * n
    return df
df1 = df1.apply(plus,axis=1,args=(2,3))    # args=(,) 传入多个参数

# apply常与lambda连用
df['考试时间']=df['考试时间'].apply(lambda x:str(x).replace('-',' ').replace(' 00:00:00',''))

var = ['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex']
titanic[var].apply(lambda x:x[2]-x[1],axis=1) # 行 跨列 列标签 

applymap() # 针对全部对象
map() # 针对series

字符串操作

s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])
s.str.lower() # 全部小写
# # 对指定列 首字母大写处理
df2['chinese'] = df2['chinese'].str.title() # 该操作不改变列名,需单独处理列名
df2['chinese'] = df2['chinese'].apply(str.title) # 两种方法等同

# 删除左右两边空格
df2['Chinese']=df2['Chinese'].astype(str).map(str.strip)
# 删除左边空格
df2['Chinese']=df2['Chinese'].map(str.lstrip)
# 删除右边空格
df2['Chinese']=df2['Chinese'].map(str.rstrip)

# 比较上下的区别
df2['Chinese']=df2['Chinese'].str.strip('$')
df['考试时间']=df['考试时间'].str.replace(' ','-')

astype()指定行列转换类型

#  使用astype函数来规范数据格式
import numpy as np

data = {'Chinese': [66,95,95,90,'test$'],'English': [65, 85, 92, 88, 90],'Math': [30, 98, 96, 98, 90]}
df2 = DataFrame(data, index=['ZhangFei', 'GuanYu', 'ZhaoYun', 'HuangZhong', 'DianWei'], columns=['English', 'Math', 'Chinese'])

df2['Math'].astype(np.int64) 
df2['Chinese'].astype(str)

map()

df['英语'] = df['英语'].map({'high':'HIGH'}) # 以字典形式传入,map不上的会变为缺失值

复合运算

# 高维和低维之间运算是广播机制

a.add(b, **argws) # 可选参数 suv mul div同理

a.mul(b,
      fill_value=0) # 同维度矩阵缺失的元素用0补齐

窗口

h.rolling(2).sum()  # 依次计算相邻两行元素的和
h.rolling(3).mean() # std var等
h.rolling(2).min.max()

分组+聚合

# 分组聚合
sex_grouped = titanic.groupby(by=['Sex','Surviv``ed'])
sex_grouped.count()['Age']
sex_grouped.mean() # 只显示数值型结果

# 聚合函数
sex_grouped.agg([np.mean,np.max,np.min])['Age']
sex_grouped.agg(['count','max','min','mean'])['Age'] # 只能针对一列

# apply 分组函数 Groupby.apply(func)
sex_grouped.apply(np.mean)[['Age','Parch']] # 一次只能接一个函数

# 针对各列分别用不同的函数
# nunique()   去掉重复值后进行计数
agg_cols={'Age':['count','max','min','mean'],'Fare':np.mean,'Parch':[np.max,'min']}
sex_grouped.agg(agg_cols)

# 如果是多列用同样的多个函数,且不需要分组,可使用同个维度的agg()
titanic[['Age','Parch']].agg(['count','max','min','mean']).round(decimals=3)

透视表与交叉表

# 数据透视表
pd.pivot_table(data=titanic,
               index='Survived',
               columns='Sex',
               values='Age',
               aggfunc=[np.mean,'max','min'],
               fill_value=0,  # 缺失补零
               margins=True,
               margins_name='total').round(2)

# 交叉表用于计算分组频率
# pd.crosstab(index,columns,margins,normalize)
pd.crosstab(index=titanic['Sex'],
            columns=titanic['Survived'],
            margins=True,
            normalize='all').round(4) 
# normalize='index'基于行的标准化

9.Pandas plot出图

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

data = pd.Series(np.random.randn(1000), index=np.arange(1000))
print(data.head(10))
print(data.cumsum()) # 累加
data.cumprod(axis=0) # 累加积,默认0为按行,改1则按列累积

data.cummax()
data.cummin()
# data本来就是一个数据,所以我们可以直接plot
data.plot()
plt.show()
# np.random.randn(1000,4) 随机生成1000行4列数据
# list("ABCD")会变为['A','B','C','D']
data = pd.DataFrame(
    np.random.randn(1000,4),
    index=np.arange(1000),
    columns=list("ABCD")
)
data.plot()
plt.show()
ax = data.plot.scatter(x='A',y='B',color='DarkBlue',label='Class1')
# 将之下这个 data 画在上一个 ax 上面
data.plot.scatter(x='A',y='C',color='LightGreen',label='Class2',ax=ax)
plt.show()

相关文章

网友评论

    本文标题:[Python] Pandas相关知识

    本文链接:https://www.haomeiwen.com/subject/scmhohtx.html