Pandas
概述
pandas
dask 比上不足比下有余
vaex
简介
数据处理,三方库,依赖于Numpy
缘起
功用
发展
竞品
资料
https://pandas.pydata.org/docs/getting_started/index.html
解构
数据分析工具pandas以DataFrame和Series为主要数据结构,DataFrame是二维表的抽象,Series为数据列的抽象,DataFrame由若干Series构成。基于DataFrame,可以进行排序、筛选、聚合、连接、透视表等操作
安装
pip install pandas
应用
pandas数据类型
…
自定义配置
import pandas as pd
# print或其他方式展示时输出所有而非省略
# 显示所有列
pd.set_option('display.max_columns', None)
# 显示所有行
pd.set_option('display.max_rows', None)
创建DataFrame
从数据结构创建
import numpy as np
import pandas as pd
ser = pd.Series(np.arange(3.))
print(ser)
import pandas as pd
df = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))
import numpy as np
import pandas as pd
df = pd.DataFrame(np.arange(16).reshape(4, 4), index=list('abcd'), columns=list('wxyz'))
import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(12).reshape(3, 4), index=['aa', 'bb', 'cc'], columns=['a', 'b', 'c', 'd'])
从文件读入
import pandas as pd
df = pd.read_json('abc.json')
df = pd.read_csv('abc.csv', sep=';', nrows=2) # 首先输入csv文本地址,然后分割符选择等等
df = pd.read_excel('foo.xlsx', 'Sheet1', index_col=None, na_values=['NA']) # 写入读取excel数据,pd.read_excel读取的数据是以DataFrame形式存储
pd.read_hdf('foo.h5','df')#写入读取HDFS数据
写入到文件
df.to_csv('abc.csv', encoding="utf8")
df.to_excel('foo.xlsx', sheet_name='Sheet1');
df.to_hdf('foo.h5','df');
多个dataframe写入一个文件
with pd.ExcelWriter("stocks.xlsx") as writer:
df1.to_excel(writer, sheet_name='df1')
df2.to_excel(writer, sheet_name='df2')
数据类型转换
pandas的dataframe数据类型转换
在使用pandas库进行数据分析时,有时候会需要将object类型转换成数值类型(float,int),那么如何做呢?
主要有以下三种方法:创建时指定类型,df.astype强制类型转换,以及使用pd.to_numeric() 转换成适当数值类型。
查看 DataFrame 数据及属性
import pandas as pd
df = pd.read_csv('estate_sales.csv')
print(df.dtypes) # 查看各行的数据格式
# Serial Number int64
# List Year int64
# Date Recorded object
# Town object
# Address object
# Assessed Value int64
# Sale Amount float64
# Sales Ratio float64
# Property Type object
# Residential Type object
# Years until sold int64
# dtype: object
print(df.head()) # 查看前几行的数据,默认前5行
# Serial Number List Year ... Residential Type Years until sold
# 0 2020348 2020 ... Nan 1
# 1 20002 2020 ... Single Family 0
# 2 200212 2020 ... Condo 1
# 3 200243 2020 ... Single Family 1
# 4 200377 2020 ... Single Family 1
print(df.tail()) # 查看后几行的数据,默认后5行
# Serial Number List Year ... Residential Type Years until sold
# 95 201078 2020 ... Single Family 0
# 96 12532 2001 ... Nan 1
# 97 200436 2020 ... Condo 1
# 98 200639 2020 ... Single Family 1
# 99 10049 2001 ... Nan 0
print(df.index) # 查看索引
# RangeIndex(start=0, stop=100, step=1)
print(df.columns) # 查看列名
# Index(['Serial Number', 'List Year', 'Date Recorded', 'Town', 'Address',
# 'Assessed Value', 'Sale Amount', 'Sales Ratio', 'Property Type',
# 'Residential Type', 'Years until sold'],
# dtype='object')
print(df.values) # 查看数据值
# [[2020348 2020 '9/13/2021' ... 'Commercial' 'Nan' 1]
# [20002 2020 '10/2/2020' ... 'Residential' 'Single Family' 0]
# [200212 2020 '3/9/2021' ... 'Residential' 'Condo' 1]
# ...
# [200436 2020 '5/4/2021' ... 'Residential' 'Condo' 1]
# [200639 2020 '7/28/2021' ... 'Residential' 'Single Family' 1]
# [10049 2001 '11/2/2001' ... 'Nan' 'Nan' 0]]
print(df.describe()) # 描述性统计
# Serial Number List Year ... Sales Ratio Years until sold
# count 1.000000e+02 100.000000 ... 100.000000 100.000000
# mean 8.504308e+05 2015.820000 ... 0.602005 0.760000
# std 3.414876e+06 7.910331 ... 0.284816 0.429235
# min 1.002900e+04 2001.000000 ... 0.000000 0.000000
# 25% 2.006150e+04 2020.000000 ... 0.499325 1.000000
# 50% 2.002205e+05 2020.000000 ... 0.581250 1.000000
# 75% 2.007105e+05 2020.000000 ... 0.682450 1.000000
# max 2.000018e+07 2020.000000 ... 1.801500 1.000000
print(df.T) # 转置
# 0 ... 99
# Serial Number 2020348 ... 10049
# List Year 2020 ... 2001
# Date Recorded 9/13/2021 ... 11/2/2001
# Town Ansonia ... Avon
# Address 230 WAKELEE AVE ... 53 HIGH GATE DR
# Assessed Value 150500 ... 367800
# Sale Amount 325000.0 ... 550000.0
# Sales Ratio 0.463 ... 0.668727
# Property Type Commercial ... Nan
# Residential Type Nan ... Nan
# Years until sold 1 ... 0
# df['col1'].astype(int)#转换某列的数据类型
基于index和column选择数据
整体上推荐使用loc或iloc方式选择数据
import numpy as np
import pandas as pd
df = pd.DataFrame(np.arange(16).reshape(4, 4), index=list('abcd'), columns=list('wxyz'))
[]形式,行选择与列选择
获取单行Series
# 不存在获取单独一行的形式,例如f['a']或df[1]
print(df[1], type(df[1]))
# Traceback (most recent call last):
# File "E:\python\pythonProject1\dfdfdf.py", line 6, in <module>
# print(df['a'])
# File "D:\Anaconda3\lib\site-packages\pandas\core\frame.py", line 3893, in __getitem__
# indexer = self.columns.get_loc(key)
# File "D:\Anaconda3\lib\site-packages\pandas\core\indexes\base.py", line 3798, in get_loc
# raise KeyError(key) from err
# KeyError: 'a'
获取多行DataFrame
# 获取index范围为[a, b)行的数据,前闭后开,返回DataFrame类型,一行也是DataFrame类型
print(df['b':'c'], type(df['b':'c']))
# w x y z
# b 4 5 6 7 <class 'pandas.core.frame.DataFrame'>
# 另外,行选择支持数字
print(df[1:2], type(df[1:2]))
获取单列Series
# 获取某一列数据,返回Series类型
print(df['w'], type(df['w']))
# a 0
# b 4
# c 8
# d 12
# Name: w, dtype: int32 <class 'pandas.core.series.Series'>
# 使用df.w可以以属性访问方式达到同样效果,有限制,需要属性存在且满足属性命名要求,df['w']为标准形式,建议使用标准形式而非属性访问形式
print(df.w, type(df.w))
获取多列DataFrame
# 获取多列数据,返回DataFrame类型
print(df[['w']], type(df[['w']]))
# w
# a 0
# b 4
# c 8
# d 12 <class 'pandas.core.frame.DataFrame'>
print(df[['w', 'y']], type(df[['w', 'y']]))
# w y
# a 0 2
# b 4 6
# c 8 10
# d 12 14 <class 'pandas.core.frame.DataFrame'>
行列组合使用
# 本质上是调用了上述两次或者多次,[]具体效果取决于数据类型,例如df[1:2][['w', 'y']]['w'][0:1]
# 首先,df[1:2] DataFrame -> DataFrame
# 其次,df[['w', 'y']] DataFrame -> DataFrame
# 再次,df['w'] DataFrame -> Series
# 最后,df[0:1] Series -> Series
# 行列组合调用多次达到区域选择效果,建议使用loc一步完成区域选择
df[1:2]['w']
df[1:2][['w', 'y']]
df[['w']][1:2]
df['w'][1:2]
df[1:2][['w', 'y']]['w'][0:1]
loc形式,区域选择
‘w’表示某一行或某一列标签
[‘w’, ‘x’]表示多行或多列标签
‘w’: ‘x’表示连续多行或连续多列,前闭后开
选择区域时若列不选择可省略,默认选择全部列
# 获取一行 Series
df.loc['a']
# 获取多行 DataFrame
df.loc[['a', 'b']] # 等价 df.loc[['a', 'b'], :]
# 获取连续多行 DataFrame
df.loc['a':'b'] # 等价 df.loc['a':'b', :]
# 获取一列 Series
df.loc[:, 'w']
# 获取多列 DataFrame
df.loc[:, ['w', 'y']]
# 获取连续多列 DataFrame
df.loc[:, 'w':'y']
# 组合可自由选择区域
# 单列单行框选单个元素df.loc['a', 'w']返回<class 'numpy.int32'>
# 单列多行或单行多列df.loc('a':'b', 'w')返回<class 'pandas.core.series.Series'>
# 多行多列df.loc[:, :]返回<class 'pandas.core.frame.DataFrame'>
iloc形式,区域选择
at形式,元素选择
基于label
选择二维表中某一个元素,返回类型为numpy类型
# 标签形式的index和column
print(data.at['a', 'w'], type(data.at['a', 'w']))
# 0
注:功能上df.at[‘a’, ‘w’]等价于df.loc[‘a’, ‘w’]
iat形式,元素选择
基于integer position
# 纯数字形式的index和column
print(data.iat[1, 1], type(data.iat[1, 1]))
# 5
注:功能上df.iat[1, 1]等价于df.iloc[1, 1]
df.ix[1:3] # 同上
df.ix[1:3,[1,3]]#获取1列3列的1~3行数据
df.columns[[0,1,3]] # zero indexed
需要注意 DataFrame 取下标和索引速度非常慢,不建议对其做 for 循环操作,若要做循环操作,建议两种替换方案,一种使用内建函数( apply、map、trasnform )等,另外一种将每列 Series 转为 list 之后处理( col_list = df.col.tolist())。
ix形式
ix 相当于 loc 和 iloc 的综合版本,既可以按标签选取,又可以按位置选取,也就是说,ix可以识别你是想按照标签选取,还是按照位置选取。
基于条件筛选数据
alist = ['023-18996609823']
df['code'].isin(alist) #将要过滤的数据放入字典中,使用isin对数据进行筛选,返回行索引以及每行筛选的结果,若匹配则返回ture
df[df['code'].isin(alist)] #获取匹配结果为ture的行
df[df.value>0]
df[df['plan'].str.contains(r'.*?语音CDMA.*')] #使用正则表达式进行模糊匹配,*匹配0或无限次,?匹配0或1次
5. 删除数据
df[columns].drop_duplicates() #剔除重复行数据
df[df.isnull()]
df[df.notnull()]
df.dropna()#将所有含有nan项的row删除
df.dropna(axis=1,thresh=3) #将在列的方向上三个为NaN的项删除
df.dropna(how='ALL')#将全部项都是nan的row删除填充值
del df.col1 # 删除列 inplace
df = df.drop('column_name', 1) # 返回删除后的新的DataFrame
df.drop('column_name', axis=1, inplace=True)
df.drop([df.columns[[0, 1, 3]]], axis=1, inplace=True) # Note: zero indexed
6. 修改数据
修改列名
df.rename(columns={'A':'a', 'C':'c'}, inplace=True)
df.columns = ['A', 'B', 'C']
df.c
df.fillna(0)
df.fillna({1:0,2:0.5}) #对第一列nan值赋0,第二列赋值0.5
df.fillna(method='ffill') #df
df['支局_维护线'] = df['支局_维护线'].str.replace('巫溪分公司(.{2,})支局','\1')#可以使用正则表达式
行列操作
df['new_column'] = df['old_column'] # 新增了一列
df.new_column = df['old_column'] # 这样不会新增列,只会跟原列起了个别名引用
# 添加尾列c,全为空白,添加尾列d,为[5,6]
data['c'] = ''
data['d'] = [5,6]
# 在第二列插入列名为c的空列,编号索引从0开始
data.insert(2,'c','')
# 删除列名为c的列
del data['c']
# 删除某行或者某列
df.drop("a", axis=0) # 删除行名为a的行
df.drop("a", axis=1) # 删除列名为a的列
7. apply
df.apply(lambda col: sum(col), axes=0) # 对每列求和
df.apply(lambda row: sum(row), axes=0) # 对每行求和
df.col2 = df.col1.apply(lambda col: sum(col)) # 对col1列求和
df.col3 = df.col3.apply(lambda x: x+1) # col3列都加1
df = df.applymap(lambda x:x+1) # 每个元素都加1
df.transform(lambda x:x+1) # 效果同上,相当于inplace的applymap
8. groupby
聚合数据(类似 SQL 中的 GROUP BY 或 HAVING)
df.groupby(['col1', 'col2']) # 将数据
data_obj.groupby('支局_维护线')['用户标识'] #上面的简单写法
adsl_obj.groupby('支局_维护线')['用户标识'].agg([('ADSL','count')])#按支局进行汇总对用户标识进行计数,并将计数列的列名命名为ADSL
9. 透视表
df = df.pivot(index='A', columes='B', values='C') # 先聚合再透视。
table = pivot_table(df, values='D', index=['A', 'B'], columns=['C'], aggfunc=np.sum) # 复杂一点的,支持同时聚合
concat
合并数据集(类似于数据库的 union/union all )
df1 = df1.append(df2) # df2放在df1后面,注意append会返回一个新的对象,不是在原对象上修改。
df = pandas.concat([df1, df2], ignore_index=True) # 等价于append
df = pandas.concat([df1, df2], axis=1) # 和sql的join类似,on index_key
join、merge
表连接
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
left_index=False, right_index=False, sort=True,
suffixes=('_x', '_y'), copy=True, indicator=False)
排序
# df.sort_values(by, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last')
import pandas as pd
df = pd.read_csv('course_score.csv')
print(df)
# 按照标签名排序
print(df.sort_index(axis=1))
# 按照值排序
print(df.sort_values(by='综合成绩', axis=0))
注意事项
SettingwithCopyWarning
Pandas经典问题
https://blog.csdn.net/richand112233/article/details/93364360
Ref
https://www.zhihu.com/tardis/zm/art/402185527
course_score.csv
学号,姓名,性别,年龄,专业,班级,课程,平时成绩,考试成绩,综合成绩
1001,张三,男,21,计算机科学与技术,2001,,56,36,92
1002,李四,女,20,国际贸易,2002,微观经济学,42,40,82
1003,,男,22,电子信息,2003,大数据导论,60,12,72
解决Pandas的to_excel()写入不同Sheet,而不会被重写
https://cloud.tencent.com/developer/article/1764213
csv只能有一页
from pandas import DataFrame
data = {'name': ['zs', 'ls', 'ww'], 'age': [11, 12, 13], 'gender': ['man', 'man', 'woman']}
df = DataFrame(data)
df.to_excel('new.xlsx', 'sheet1')
df.to_excel('new.xlsx', 'sheet2')