5.pandas

予早 2025-02-21 01:08:21
Categories: Tags:

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形式,区域选择

# 获取一行 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')