Bootstrap

Python数据分析常用函数

Python基础

数字处理函数

Python提供了用于数字处理的内置函数和内置模块(math),使用内置模块,需要先导入 import math。

内置函数math模块
abs(-5)返回绝对值math.ceil(2.3)返回不小于x的最小整数
divmod(9,4)返回商和余数math.floor(2.3)返回不大于x的最大整数
eval('a*a+1')返回字符串中的表达式结果math.fabs(-5)返回x的绝对值
max(1,2,3,4)返回最大值math.factorial(5)返回非负数x的阶乘
min(1,2,3,4)返回最小值math.fmod(9,4)返回x除于y的余数
pow(2,3)返回2的3次方,等价于2**3math.fsum([0.1,0.1,0.1,0.1])求和,比sum更精确
round(1,56)四舍五入,只有一个参数是返回整数math.gcd(12,8)返回xy的最大公约数
round(1.567,2)四舍五入,保留2为小数math.trunc(15.67)返回x的整数部分
sum({1,2,3,4})求和math.pi返回π值,3.141592653589793

字符串的切片

字符串的切片也称分片,它利用索引范围从字符串中获得连续的多个字符(即子字符串)。字符串切片的基本格式:x[ start : end : step],返回字符串x中从偏移量start开始、到偏移量end之前的子字符串,切片默认情况下是返回字符串中的多个连续字符,可以通过step步长参数来跳过中间的字符。startendstep参数均可省略,start默认为0end默认为字符串长度step默认为1

x = 'abcdef'
print(x[1:4])  # 返回偏移量为1到3的字符  bcd
print(x[1:])  # 返回偏移量为1到末尾的字符  bcdef
print(x[:4])  # 返回从字符串开头到偏移量为3的字符  abcd
print(x[:-1])  # 除最后一个字符,其他字符全部返回  abcde
print(x[:])  # 返回全部字符  abcdef
x = '0123456789'
print(x[1:7:2])  # 返回偏移量为1、3、5的字符  135
print(x[::2])  # 返回偏移量为偶数的全部字符  02468
print(x[7:1:-2])  # 返回偏移量为7、5、3的字符  753
print(x[::-1])  # 将字符串反序返回  9876543210

字符串是有序的字符集合,可用for循环迭代处理字符串,for item in 'abcdefghijk': print(item,end='\t')

字符串处理函数

字符串是 str 类型的对象,Python提供了一系列方法用于字符串的处理。常用的字符串处理方法如下:

方法名描述
len(str)返回 str 的长度,即包含的字符个数
str(info)将非字符串数据转换为字符串
capitalize(str)将字符串第一个字母大写,其余字母小写,返回新的字符串
count(sub[, start[, end]])返回字符串sub在当前字符串的[start, end]范围内出现的次数,省略范围时会查找整个字符串
startswith(prefix[, start[, end]])判断当前字符串的[start, end]范围内的子字符串是否以sub字符串开始
endswith(suffix,[, start[, end]])判断当前字符串的[start, end]范围内的子字符串是否以sub字符串结尾
find(sub[, start[, end]])在当前字符串的[start, end]范围内查找子字符串sub,返回sub第一次出现的位置,没有找到时返回-1
format(args)字符串格式化,将字符串中用{}定义的替换域依次用参数args中的数据替换,print('My name is {0},age is {1}'.format('Tome', 23))
ljust/rjust(width[, fillchar]) 当字符串长度小于width时,在字符串末尾填充fillchar,使其长度等于width。默认填充字符为空格
lower()/upper()将字符串中的字母全部转换成小写/大写
replace(old, new[, count])将当前字符串包含的old字符串替换为new字符串,省略count时会替换全部old字符串。指定count时,最多替换count
split([sep],[maxsplit])将字符串按照sep指定的分隔字符串分解,返回包含分解结构的列表。省略sep时,以空格作为分隔符
'sep'.join(iterable)按照sep指定的分割符连接序列对象(iterable),返回拼接后的字符串

日期和时间数据类型

Python标准库中包含用于日期、时间、日历数据的数据类型,主要用到datetimetimecalendar模块。

函数说明
datetime.datetime.now()获取当前系统时间
datetime.date(year,month,day)日期(年、月、日)
datetime.time(hour, minute, second, microsecond, tzinfo)时间(时、分、秒、毫秒)
datetime.datetime(year, month, day,hour, minute, second, microsecond, tzinfo)日期和时间
datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)两个datetime的差(日、秒、毫秒),也可以做日期加减运算
datetime.tzinfo()用于存储时区信息的基本类型
datetime.datetime.strptime(datetime_str, formatter)把字符串日期转为日期对象
datetime_obj.strftime(formattter)把日期对象转为指定格式的字符串
import datetime 

datetime.datetime.now()    # 获取当前系统时间
date = datetime.date(2019,11,12)   # 封装指定日期
print(date.year,date.month,date.day)    # 获取年月日
date = datetime.time(23,12,12,100)     # 封装指定时间
print(date.hour,date.minute,date.second,date.microsecond)    # 获取时分秒
datetime.datetime.now()+datetime.timedelta(-10) # 日期加减操作
# 日期相差结果,注意需要保证类型一致
delta = datetime.datetime.now() - datetime.datetime(2019,11,12,23,12,12)  # datetime.timedelta(days=1479, seconds=37384, microseconds=61401)
delta.seconds  # 获取相差的秒数

datetime.datetime.strptime('2019-11-12','%Y-%m-%d')  # 日期字符串转为日期对象
datetime.datetime.now().strftime('%Y年%m月%d日')   # 日期对象转为指定格式的字符串

列表

列表是Python中最具灵活性的有序集合对象类型。和字符串不同的是,列表具有可变长度、异构以及任意嵌套列表的特点。列表是可变对象,支持在原处修改。
列表常量用方括号表示,例如,[1,2,'abc'],也可以使用list()函数来创建。

列表基本操作包括:创建列表求长度合并重复迭代关系判断索引分片等。

函数名称说明
append(item)在列表末尾添加一个数据
del删除列表中指定数据或分片
count(item)返回item在列表中出现的次数
clear()删除列表中的全部数据
insert(index,item)在指定位置插入数据
index(item)返回列表中第一个值为item的元素的索引
remove(item)用于删除列表中的指定值,如果有重复值,则删除第1个
reverse()将列表中数据的位置反转
pop([index])用于删除指定位置的对象,省略位置时删除列表的最后一个对象,同时返回被删除的对象
sort([key=func, reverse=True/False])将列表排序,若列表对象全部是数字,则将数字从小到大排序。若列表对象全部是字符串,则按字典顺序排序。它还支持自定义排序,可用key参数指定一个函数,sort方法将列表元素作为参数调用该函数,用函数返回值代替列表元素完成排序。
# 创建列表
print([1, 2, 3, 4, ('a', 'b'), [12, 34]])  # [1, 2, 3, 4, ('a', 'b'), [12, 34]]
print(list('abcd'))                        # ['a', 'b', 'c', 'd']
print(list(range(-2, 3)))                  # [-2, -1, 0, 1, 2]

# 求长度
print(len([1, 2, 3, 4, ('a', 'b'), [5, 6]]))  # 6

# 合并
print([1, 2] + ['abc', 20])

# 重复
print([1, 2] * 5)

# 关系判断
print(2 in [1, 2, 3])

# 分片
list1 = list(range(10))
print(list1[:5])       # [0, 1, 2, 3, 4]
print(list1[3:10:2])   # [3, 5, 7, 9]
print(list1[10:3:-2])  # [9, 7, 5]

list1 = [1, 2]
del list1[0]   # 删除第1个元素
list1.clear()  # 清空列表

# 排序
price_list = [{'price': 76}, {'price': 99}, {'price': 84}]
price_list.sort(key=lambda item: item.get('price'))
print(price_list)  # [{'price': 76}, {'price': 84}, {'price': 99}]

列表推导式

列表推导式提供了从序列创建列表的简单途径。通常应用程序将一些操作应用于某个推导序列的每个元素,用其获得的结果作为生成新列表的元素,或者根据确定的判定条件创建子序列。
语法格式为:[ <expr1> for k in L if <expr2> ]
在这里插入图片描述

元组

元组是一种固定长度、不可变的Python对象序列。元组和字符串一样,不可改变,即不能给元组的一个独立的元素赋值。元组和列表看起来不同的一点是:元组用的是圆括号(),而列表用的是方括号[]
与字符串一样,元组之间可以使用 + 号和 * 号进行运算。

# 创建元组
print((2,))  # 包含一个对象的元组,不能缺少逗号  (2,)
print(tuple('abcde'))  # 参数为可迭代对象  ('a', 'b', 'c', 'd', 'e')
print(tuple(item * 2 for item in range(5)))  # 使用解析结构创建元组  (0, 2, 4, 6, 8)

# 求长度
print(len((1, 2, 3, 4, 5)))  # 5

# 合并
t1 = (1, 2) + ('ab', 'cd') + (2.45,)  # (1, 2, 'ab', 'cd', 2.45)
print(t1)

# 重复
print((1, 2) * 3)  # (1, 2, 1, 2, 1, 2)

# 关系判断
print(2 in t1)  # True

# 索引和分片
t2 = tuple(range(10))  # (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
print(t2[1])           # 1
print(t2[-1])          # 9
print(t2[2:5])         # (2, 3, 4)

# #元组的拆分
a,b,c = (1, 5, 7)
print(a, b, c)

字典

字典,也称映射,是一个由键/值对组成的非排序可变集合体。键值对在字典中以下面的方式标记: dict = {key1 : value1, key2 : value2 }
键/值对用冒号分割,而各个元素之间用逗号分割,所有元素都包括在花括号中。值得注意的是,字典中的键必须是唯一的,只能使用不可变的对象来作为字典的键,字典中的键/值对是没有顺序的。

函数名称说明
clear()删除全部字典对象
copy()复制字典对象
get(key[,default])返回键 key映射的值。如果键key不存在,返回空值,可用default参数指定键不存在时的返回值。
pop(key[,default])从字典中删除键值对,并返回被删除的映射值。若键不存在,则返回default。若键不存在且未指定default参数时,删除键会出错。
popitem()从字典中删除键值对,同时返回被删除的键值对元组。空字典调用该方法会产生KeyError错误。
setdefault(key[,default])用于返回映射值或者为字典添加键值对。指定的键key在字典中存在时,返回其映射值。若指定的键key不存在,则将键值对key:default添加到字典中。省略default时,添加的映射值默认为None
update(other)update()方法用于为字典添加键值对。参数other可以时另一个字典或用赋值格式表示的元组。若字典已存在同名的键,则该键的映射值被覆盖。
items()返回键值对视图,视图对象支持迭代操作,不支持索引。当字典对象发生改变时,字典视图可实时反映字典的改变
keys()返回字典中所有键的视图
values()返回字典中全部值的视图
x = dict(name='Tom', age=25)
y = x
# 复制字典对象
yc = x.copy()
print(y is x, yc is x)  # 判断是否引用相同对象 True False

# 获取指定key映射的值
print(x.get('name'))  # 返回映射值  Tom
print(x.get('addr'))  # 不存在的键返回空值  None
print(x.get('addr', 'xxx'))  # 不存在的键返回指定值  xxx

# 获取或添加
print(x.setdefault('name'))  # 返回指定键的映射值  Tom
print(x.setdefault('sex'))  # 键不存在,为字典添加“键:值”对,映射值默认为None  None
print(x.setdefault('addr', 'CQ'))  # 添加“键:值”对  CQ
print(x)  # {'name': 'Tom', 'age': 25, 'sex': None, 'addr': 'CQ'}

# 添加或修改
x.update({'age': 30, 'sex': '女'})  # 添加“键:值”对,并覆盖同名键的映射值
print(x)  # {'name': 'Tom', 'age': 30, 'sex': '女', 'addr': 'CQ'}
x.update(name='Mike')  # 修改映射值
x.update(code=110, tel='123456')  # 添加“键:值”对
print(x)  # {'name': 'Mike', 'age': 30, 'sex': '女', 'addr': 'CQ', 'code': 110, 'tel': '123456'}

# 删除指定key的键值对象
print(x.pop('name'))  # 删除键并返回映射值  Mike
print(x.pop('id', 'xxx'))  # 删除不存在的键,返回default参数值  xxx
# print(x.pop('other'))  # 删除不存在的键,未指定default参数,出错 KeyError: 'other'

# 删除字典元素,并以元组的形式返回删除的元素,如果字典为空,则报错 KeyError: 'popitem(): dictionary is empty'
print(x.popitem())  # ('tel', '123456')

# 返回 键值对 视图
entity = x.items()  # dict_items([('age', 30), ('sex', '女'), ('addr', 'CQ'), ('code', 110)])
print(list(entity))  # [('age', 30), ('sex', '女'), ('addr', 'CQ'), ('code', 110)]

# 返回 键 视图,值 视图
keys = x.keys()  # dict_keys(['age', 'sex', 'addr', 'code'])
vals = x.values() # dict_values([30, '女', 'CQ', 110])

集合

集合是一个由唯一元素组成的非排序集合体。也就是说,集合中的元素没有特定顺序,集合中没有重复项。可以使用大括号{ }或者set()函数创建集合,但是,创建一个空集合必须用 set(),因为{ }是用来创建一个空字典
集合对象元素的值不支持修改,但是可以复制集合、为集合添加删除元素。

函数名称说明
copy().复制集合对象
remove(item)/discard(item)删除指定元素,删除不存在时会报错/删除不存在时不会报错
add(item)添加一个元素
pop()随机删除一个元素,并返回该元素
update({item1,item2,...})添加多个元素
clear()删除集合中的全部元素
x = {1, 2}
print(x.copy())    # 复制集合对象
x.add('abc')       # 为集合添加一个元素
x.update({10, 20}) # 为集合添加多个元素
x.remove(10)       # 从集合中删除指定元素,删除不存在元素时会报错
x.discard(15)      # 移除元素
print(x.pop())     # 从集合中随机删除一个元素,并返回该元素 1
x.clear()          # 删除集合中的全部元素  set()

集合元素是不可改变的,因此不能将可变对象放入集合中;集合、列表和字典对象均不能加入集合;元组可以作为一个元素加入集合

Series

Series是一个类似一维数组的对象,它能够保存任何类型的数据,主要由一组数据和与之相关的索引两部分构成。
Pandas的Series类对象的创建语法:pandas.Series(data=None, index=None, dtype=None, copy=False)

  • data:表示传入的数据。
  • index:表示索引,唯一且与数据长度相等,默认会自动创建一个从0~N的整数索引。
  • dtype:数据的类型。
  • copy:是否复制数据,默认是False。
s1 = pd.Series([1,2,3,4,5],index=['a','b',1,8,9],name="nums")
s1.index   		# Index(['a', 'b', 1, 8, 9], dtype='object')
s1.values 		# array([1, 2, 3, 4, 5], dtype=int64)
type(s1.values) # numpy.ndarray
s1 + 10
s1.sum()
s1[8]     		# 通过索引取值
s1[s1>3]  		# 通过条件取值

Series常用方法

  • Series.unique():去除重复元素
  • Series.nunique():统计去重后的元素个数
  • Series.isnull():检测那些元素为空,为空则返回True
  • Series.notnull():检测那些元素为非空,不为空的返回Ture

DataFrame

DataFrame是一个类似于二维数组或表格的对象,它每列的数据可以是不同的数据类型。与Serise的结构相似,DataFrame的结构也是由索引和数据组成的,不同的是,DataFrame的索引不仅有行索引,还有列索引,数据可以有多列。
Pandas的DataFrame类对象的创建语法:pandas.DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)

  • index:行标签。若不设置该参数,则默认会自动创建一个从0~N的整数索引。
  • columns:列标签。若不设置,同样会自动创建一个从0~N的整数索引。

DataFrame常用属性和方法

  • df.head() 默认获取前5行
  • df.head(n) 获取前n行
  • df.tail() 默认获取后5行
  • df.tail(n) 获取后n行
  • df.sample(n) 随机抽取n行显示
  • df.sample(frac=0.6) 随机抽取60%的行
  • df.info() 获取对象中元素的完整信息,包括行/列标签、数据类型、是否有空值、占用的内存大小等
  • df.index 获取所有行标签
  • df.columns 获取所有列标签
  • df.values获取所有元素的值
  • df.T 对象中元素的行/列数据转换

DataFrame数据的查询

在数据分析中,选取需要的数据进行分析处理是最基本的操作,在Pandas中通过索引完成数据的选取,除了使用之前学过的切片,还可以使用如下方法。

  1. df.loc[行索引名称或条件[, 列索引名称]]:基于标签索引,用于按标签名称或条件选取数据。当执行切片操作时,既包含起始索引,也包含结束索引
emp_df.loc[0:2,["job","sal"]]
emp_df.loc[emp_df.sal>1500, ["ename","job","sal"]]
emp_df.loc[0:3,'mgr':'sal']
  1. 布尔选择:对行数据可以使用条件进行过滤,多条件的逻辑运算符使用&|!=== ,并使用圆括号来明确指定条件的优先级,避免歧义。
emp_df.loc[(emp_df.sal>1500) & (emp_df.sal<3000), ["ename","sal","job"]]
emp_df[(emp_df.sal>1500) &(emp_df.sal<3000)][["ename","sal"]]
  1. df.iloc[行索引位置,列索引位置]:只能使用整数索引,不能使用标签索引来选取数据。当执行切片操作时,包含起始索引,也包含结束索引。
emp_df.iloc[2:5, 2:5]
  1. df.query(expr, inplace=False):使用类似于SQL的表达式筛选数据,并返回筛选后的结果,注意在使用的列名中的空格要用_`替换,字段名区分大小写且等于判断必须使用双等号。
    • expr: 字符串形式的SQL表达式,用于过滤数据。
    • inplace: 如果是的话,在原始数据框中进行修改
emp_df.query("sal>1500 and job=='MANAGER'")

data.columns =[column.replace(" ", "_") for column in data.columns]把列名中的空格替换为下划线

函数应用与映射

在数据分析时,经常会对数据进行较复杂的运算,此时需要定义函数,定义好的函数可以应用到Pandas,数据中,有三种方法可以实现。

  1. map,将函数套用到Series的每个元素中。参数可以传递字典,进行指定数据1对1映射替换。

  2. apply,将函数套用到DataFrame的行与列上,行与列通过axis参数设置。也可以作用于Series上,效果比map好。

  3. applymap,将函数套用到DataFrame的每个元素上。

排序

在数据处理中,数据的排序也是常见的一种操作。由于Pandas中存放的是索引和数据的组合,索引它既可以按索引进行排序,也可以按数据进行排序。

  • df.sort_index(axis=0,ascending=True,inplace=False):按索引排序,该方法可以用行索引或者列索引进行排序。
    • axis:轴索引,0表示index,即按行排序;1表示columns,即按列排序。
    • ascending:是否升序排列,默认为True,表示升序。
    • inplace:表示对数据进行排序,不创建新的实例。
  • df.sort_values(by,axios=0,ascending=True,inplace=False,na_position='last'):按值排序。
    • by:表示排序的列。
    • np_position:表示NaN的值放在开头(first)还是最后(last),默认是最后。
# DataFrame中指定列排序
emp_df.sort_values("sal",inplace=True)
# Series排序
emp_df.sal.sort_values(ascending=False)

数据聚合-aggregate

aggaggregate方法都支持对每个分组应用某个函数,包括Python内置函数或自定义函数。同时,这两个方法也能直接对DataFrame进行函数应用操作。

df['sal'].agg(['sum','max','min','mean'])
df['sal'].agg([('总薪资','sum'),('平均薪资','mean')])
df['sal'].agg({'总薪资',np.sum,'平均薪资',np.mean})

# agg返回一个聚合分组
df[['deptno','sal']].groupby('deptno').agg(np.sum)

# agg返回两个聚合分组
result = df[['deptno','sal']].groupby('deptno').agg([np.sum,np.mean])
result.sal['sum']

# 自定义函数
def count(item):
    return len(item)
    
emp_df.groupby('deptno')['sal'].agg([np.sum,np.max,np.mean,count])

分组运算-transform

agg是将函数应用于每一列,返回分组后的聚合结果,而transform方法可以将运算分布到每一行,类似于窗口函数,在求比例的时候比较有用。

emp_df.groupby('deptno')['sal'].agg(np.mean)

# 求每个员工薪资,占部门总薪资的百分比
result_df = emp_df.groupby('deptno')[['deptno','sal']].transform(np.sum)
result_df['emp_sal'] = emp_df['sal']

# # 求每个部门中员工薪资占部门总薪资的百分比
dept_total_sal = emp_df.groupby('deptno')['sal'].transform(np.sum)
emp_df['dept_total_sal'] = dept_total_sal
round(emp_df.sal / emp_df.dept_total_sal * 100,2).astype('string') + '%'

加减时间数据

时间数据的算术运算在现实中随处可见,例如,2020年1月1日减一天就是2019年12月31日。pandas的时间数据和现实生活中的时间数据一样可以做运算。这时就涉及Pandas的**Timedelta**类。
Timedelta是时间相关类中的一个异类,不仅能够使用正数,还能够使用负数表示单位时间,如1s、2min、3h等。使用Timedelta类,配合常规的时间相关类能够轻松实现时间的算术运算。
在Timedelta类的时间周期中没有年和月,所有周期名称、对应单位及其说明如下表:

周期名称单位说明周期名称单位说明
weeks星期secondss
daysDmillisecondsms毫秒
hoursh小时microsecondsus微妙
minutesmnanosecondsns纳秒
pd.Timedelta("1 days")  # Timedelta('1 days 00:00:00')
pd.Timedelta("1 days 2 hours") # Timedelta('-2 days +23:57:57')
pd.Timedelta(pd.offsets.Second(2)) # Timedelta('0 days 00:00:02')
pd.Timedelta(pd.offsets.Minute(-2)) # Timedelta('-1 days +23:58:00')

# 时间加减
result = music_df['date'] + pd.Timedelta("1 days")
result.head(3)

Pandas高级接口

Series对象和DataFrame的列数据提供了catdtstr三种属性接口,分别对应分类数据、日期时间数据和字符串数据,通过这几个接口可以快速实现特定的功能,非常快捷。

.dt(日期时间数据)

.dt 属性主要用于处理日期时间数据。当你有一个包含日期时间对象的 Series 或 DataFrame 列时,你可以使用 .dt 访问器来执行各种日期和时间相关的操作,如提取年份、月份、日期、时间等。

  • pandas.to_datetime(date) :将数据列表中的 Series 列转化为 datetime 类型。
  • series.dt.strftime('%Y-%m-%d %H:%M:%S'):将日期数据转换为指定格式的字符串。
  • series.dt.date/year/month/day/hour/time/quarter/weekday:提取日期类型数据的年 / 月 / 日 / 时 / 分 / 秒 / 季度 / 星期。
import pandas as pd  
  
# 创建一个包含日期时间的Series  
s = pd.Series(pd.date_range('2023-01-01', periods=5))  
  
# 使用.dt属性提取年份  
print(s.dt.year)  
  
# 提取月份、日期等  
print(s.dt.month)  
print(s.dt.day)

dt常用方法

1. 提取日期时间组件
   - dt.year:提取年份。
   - dt.month:提取月份。
   - dt.day:提取日期。
   - dt.hour:提取小时(对于 datetime 对象)。
   - dt.minute:提取分钟(对于 datetime 对象)。
   - dt.second:提取秒(对于 datetime 对象)。
   - dt.microsecond:提取微秒(对于 datetime 对象)。
2. 日期时间的格式化
   - dt.strftime(date_format):将日期时间对象格式化为字符串。例如,df['date'].dt.strftime('%Y-%m-%d') 会将日期时间列格式化为 "YYYY-MM-DD" 的形式。
3. 日期时间的属性
   - dt.date:返回日期时间对象的日期部分(只包含年月日)。
   - dt.normalize():将日期时间对象规范化为午夜(00:00:00)。
   - dt.time:返回日期时间对象的时间部分(只包含时分秒)。
4. 日期时间的计算和判断
   - dt.weekday 或 dt.weekday_name:返回日期是星期几(0 表示星期一,6 表示星期日;或返回星期几的字符串名称)。
   - dt.week 或 dt.weekofyear:返回日期是一年中的第几周。
   - dt.dayofweek:返回日期是星期几(0 表示星期一,6 表示星期日,与 dt.weekday 相同,但返回的是整数)。
   - dt.dayofyear:返回日期是一年中的第几天。
   - dt.quarter:返回日期是第几季度(14)。
   - dt.is_leap_year:判断年份是否为闰年。
   - dt.is_month_start、dt.is_month_end、dt.is_quarter_start、dt.is_quarter_end、dt.is_year_start、dt.is_year_end:判断日期是否是一个月、季度或年的开始或结束。
5. 日期时间的算术运算
   - 你可以对日期时间进行算术运算,如加法、减法,以调整日期时间。例如,df['date'] + pd.Timedelta(days=1) 会将日期时间列中的每个日期增加一天。
6. 时间差
   - 你可以使用 dt.diff() 来计算两个连续日期时间之间的差异(返回一个包含时间差的 Series)。

.str(字符串数据)

.str 属性用于处理字符串数据。当你有一个包含字符串的 Series 或 DataFrame 列时,.str 访问器提供了许多用于字符串操作的便捷方法,如字符串切片、大小写转换、查找和替换等。

import pandas as pd  
  
# 创建一个包含字符串的Series  
s = pd.Series(['apple', 'banana', 'cherry', 'date'])  
  
# 使用.str属性转换为小写  
print(s.str.lower())  
  
# 查找并替换字符串中的子串  
print(s.str.replace('a', 'o'))  
  
# 使用.str.contains检查是否包含某个子串  
print(s.str.contains('a'))

str常用方法

1. 大小写转换
   - str.lower(): 将字符串转换为小写。
   - str.upper(): 将字符串转换为大写。
   - str.capitalize(): 将字符串的首字母转换为大写,其余部分转换为小写。
   - str.swapcase(): 反转字符串中所有字母的大小写。
2. 字符串的匹配和查找
   - str.contains(pattern, [case=True], [na=nan], [regex=True]): 判断字符串是否包含指定的子串或正则表达式模式。
   - str.startswith(pat, [na=nan])str.endswith(pat, [na=nan]): 判断字符串是否以指定的前缀或后缀开始或结束。
   - str.find(sub[, start[, end]])str.rfind(sub[, start[, end]]): 查找子串在字符串中的位置,rfind从右向左查找。
3. 字符串的替换
   - str.replace(pat, repl[, n=-1[, case=True[, regex=False[, flags=0]]]]): 替换字符串中的子串或正则表达式模式。
4. 字符串的分割和连接
   - str.split(pat=None, n=-1, expand=False): 使用指定的分隔符将字符串分割为子串列表。
   - str.rsplit(pat=None, n=-1, expand=False): 从右向左分割字符串。
   - str.cat(others=None, sep=None, na_rep=None, join_axes=None): 连接多个字符串。
5. 字符串的切片和提取
   - str.slice(start=None, stop=None, step=None): 提取字符串的子串(类似于Python的切片操作)。
   - str.slice_replace(start=None, stop=None, repl=None): 替换字符串中指定范围的子串。
   - str.get(i): 获取指定位置的字符(只能获取一个)。
   - str.extract(pat, expand=None): 使用正则表达式从字符串中提取匹配项。
6. 字符串的修改和清理
   - str.strip([to_strip]), str.lstrip([to_strip]), str.rstrip([to_strip]): 删除字符串两端、左侧或右侧的指定字符(默认为空白字符)。
   - str.zfill(width): 使用零填充字符串的左侧,直到达到指定的宽度。
   - str.pad(width, side='left', fillchar=' '): 在字符串的左侧、右侧或两侧填充指定的字符,直到达到指定的宽度。
   - str.wrap(width, **kwargs): 将字符串在指定的宽度处换行。
   - str.justify(width, mode='left', fillchar=' '): 对字符串进行对齐操作。
7. 字符串的长度和计数
   - str.len(): 返回字符串的长度。
   - str.count(pat, [start[, end]]): 返回子串在字符串中出现的次数。
8. 字符串的排序和比较
   - str.sort_values(): 当在DataFrame中使用时,可以根据字符串列的值对行进行排序。
   - str.compare(other, na_equality=None): 比较两个字符串对象是否相等。

数据清洗

数据清洗是一项复杂且繁琐的工作,同时也是整个数据过程中最为重要的环节。
数据分析的目的在于提高数据质量,将脏数据(没有实际意义、格式非法、不完整的、有噪声和不一致的数据)清洗干净,使原数据具有完整性、唯一性、权威性、合法性、一致性等特点。Pandas中常见的数据清洗操作有空值和缺失值的处理、重复值的处理、异常值的处理、统一数据格式等。

空值和缺失值的处理

一般空值使用None表示,缺失值使用NaN表示。Pandas中提供了一些用于检查或处理空值和异常值的函数,其中isnullnotnull()函数可以判断数据集中是否存在空值和缺失值,对于缺失数据可以使用dropna()fillna()方法进行删除和填充。

  • Series/DataFrame.isnull()/pandas.isnull(obj):检查空值对象。一旦发现数据中存在NaN或None,则将这个位置标记为True,否则就标记为False。
  • Series/DataFrame.notnull()/pandas.notnull(obj):检查非空值对象。一旦发现有空值或缺失值时返回False。
  • DataFrame.any(axis=0)/DataFrame.all(axis=0):指定列或行中是否有指定数据或者全部数据。可配合空判断,检测所在行或列是否有空值。
    • df.notnull().all(axis=1) / df.isnull().any(axis=1) / df.loc[~(df.isnull().any(axis=1))]:检测数据行中是否有缺失数据,~是取反
    • indexs = df.loc[df.isnull().any(axis=1)].index``df.drop(labes=indexs, axis=0):drop开头的axis和其他类型的axis的取值刚好相反。
  • Series/DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False):删除含有空值或缺失值的行或列。
    • axis:确定过滤行或列,取值可以为0或index、1或columns,默认是0。
    • how:确定过滤的标准,取值可以为any表示如果存在则删除该行或列、all则需要所有值都是NaN,默认是any。
    • thresh:表示有效数据量的最小要求。若传入了2,则是要求该行或该列至少有两个非NaN值时将其保留。
    • subset:表示在特定的子集中寻找NaN。
  • Series/DataFrame.fillna(value=None, method=None, axis=None, inplace=False):填充空值或缺失值。
    • value:用于填充的数值。
    • method:表示填充方式,默认值为None,取值有pad/ffill表示用缺失值的前面的一个值填充、backfill/bfill表示缺失值后面一个值填充。注意:method参数不能与value参数同时使用。
# 测试数据
df = pd.DataFrame({"类别":['小说', '散文随笔', '青春文学', '传记'],
                   "书名":[np.nan, '《皮囊》', '《旅程结束时》', '《老舍自传》'],
                   "作者":["老舍", None, "张其鑫", "老舍"]})
# 空值和缺失值检测
pd.isnull(df["书名"])  # df.isnull()
pd.notnull(df["书名"]) # df.notnull()
df[pd.isnull(df["书名"])]  # 获取书名为空的数据
df.isnull().all(axis=1) # 获取全部为空的行
df.isnull().any(axis=1).sum() # 含有缺失值的行有多少个

# 空值和缺失值删除
df.dropna(subset=['书名'])

# 空值和缺失值填充
df.fillna('未知') # 使用【未知】填充缺失值和空值
df.fillna({'书名':'《未知》','作者':'未知'})  # 指定具体列的填充数据
df.fillna(method='bfill')  # 使用缺失值的后一个值填充

重复值的处理

当数据中出现了重复值,在大多数情况下需要进行删除。
Pandas提供了两个函数专门用来处理数据中的重复值,分别为duplicated()drop_duplicates()方法。

  • duplicated(subset=None, keep='first', inplace=False):用于标记是否有重复值,只要两条数据中所有条目的值完全相等,就判断为重复值,标记为True。
    • subset:用于识别重复的列标签或列标签序列,默认识别所有的列标签。
    • keep:删除重复项并保留第一次出现的项,取值可以为first(除第一次出现外,其余相同的都标记重复)、last或False(所有相同的都标记为重复)。
  • drop_duplicates():用于删除重复值,判断标准与duplicated()一致。
  • Series.unique():去除重复元素
  • Series.nunique():统计去重后的元素个数
  • Series.value_counts():统计不同元素出现的次数
  • Series.map({val1:val2,val3:val4}):映射,把一个数据映射为另一个数据,返回一个新的Series列。参数可以是字典,也可以是lambda函数
df = pd.DataFrame({'id': [1, 2, 3, 4, 4, 5],
                   'name': ['小铭', '小月月', '彭岩', '刘华', '刘华', '周华'],
                   'age': [18, 18, 29, 58, 58, 36],
                   'height': [180, 180, 185, 175, 175, 178],
                   'gender': ['女', '女', '男', '男', '男', '男']})

df.duplicated(keep=False)  # 检查是否有重复值,标记所有重复行
df.drop_duplicates(keep='first')  # 删除后一个重复行

异常值的处理

异常值是指样本中的个别值,其数值明显偏离它所属样本的其余观测值。异常值的存在会严重干扰数据分析的结果,因此经常要检验数据中是否有输入错误或含有不合理的数据。在数据统计方法中一般常用散点图、箱线图等方式检测异常值。

df = pd.DataFrame(np.arange(20),columns=['X'])
df['Y'] = df['X'] * 1.5 + 2
df.iloc[3,1] = 48
df.iloc[18,1] = 40
df.plot(kind='scatter',x='X',y='Y',grid=True)
df = pd.DataFrame({'A':[1,2,3,4],
                   'B':[2,3,25,2],
                   'C':[1,4,7,4],
                   'D':[1,5,30,3]})
df.boxplot()

# 获取异常值
fig = df.boxplot(column='B',return_type='dict') 
min = fig['caps'][0].get_ydata()[0]  # 下界值
max = fig['caps'][1].get_ydata()[0]  # 上界值
df[df['B'] > max]
;