pandas 数据处理

本文涉及的产品
实时数仓Hologres,5000CU*H 100GB 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
实时计算 Flink 版,5000CU*H 3个月
简介: pandas 数据处理

pandas 数据清洗

1. 去除 NaN 值

在Pandas的各类数据Series和DataFrame里字段值为NaN的为缺失数据,不代表0而是说没有赋值数据,类似于python中的None值。数据的缺失有很多原因,缺失不是错误、无效,需要对缺失的数据进行必要的技术处理,以便后续的计算、统计。

可以通过numpy 模块的 nan 得到NaN 值。

首先,可以通过isnull 和 notnull 方法查看有哪些NaN值,这两个方法返回的布尔值,指示该值是否是NaN值,结合sum 方法可以获取每列空值的数目以及总数。也可以通过 count 方法得到每列不为NaN值的数目。

dropna()

删除NaN 值 可以通过 dropna 方法,默认按行扫描(操作),会将每一行有NaN 值的那一行删除,同时默认是对原对象的副本操作,不会对原对象产生影响,也可以通过inplace 指示是否直接在原对象上操作。
示例:

import pandas as pd
import numpy as np
val = np.arange(10, 38).reshape(7, 4)
col = list("abcd")
idx = "cake make fake sake wake lake take".split()
df = pd.DataFrame(val, columns = col, index = idx)
df["e"] = np.nan
df.at["make", "e"] = 100
print(df)
print(df.dropna())
print(df)

"""
       a   b   c   d    e    print(df)
cake  10  11  12  13  NaN
make  14  15  16  17  100
fake  18  19  20  21  NaN
sake  22  23  24  25  NaN
wake  26  27  28  29  NaN
lake  30  31  32  33  NaN
take  34  35  36  37  NaN
       a   b   c   d    e    print(df.dropna())
make  14  15  16  17  100
       a   b   c   d    e    print(df)
cake  10  11  12  13  NaN
make  14  15  16  17  100
fake  18  19  20  21  NaN
sake  22  23  24  25  NaN
wake  26  27  28  29  NaN
lake  30  31  32  33  NaN
"""

dropna 方法可以选择删除

# 要删除一列或一行中全部都是nan 值的那一行或列,可以通过下面的方式 
print("del cols is all NaN\n", df.dropna(axis = 'columns', how='all'))    # how='all'  指明要这一列全部是nan值才删除,axis 案列操作
print("del rows is all NaN\n", df.dropna(axis = 'rows', how='all'))    # axis 按行操作,how 原理同上


# 同时可以添加条件删除
print(df.dropna(axis = 1, thresh = 2))    # axis=1按列操作,thresh 指示这一列或行中有两个或以上的非NaN 值的行或列被保留

通过布尔判断,也是可以实现删除 NaN 的功能。

# 使用布尔逻辑判断,下面两句代码功能一致。
print(df.e[df.e.notnull()])
print(df.e.dropna())

2. 填充NaN 值

一般情况下直接将NaN删除或许并不是最好的选择因此可以通过将NaN值进行填充。

fillna()

fillna 方法可以将df 中的nan 值按需求填充成某值

# 将NaN值用0填充
df.fillna(0,inplace = True)    # inplace 指明在原对象上直接修改

复杂的 使用向前 或 向后 填充数据,依旧使用fillna 方法,所谓向前 是指 取出现NaN值的前一列或前一行的数据来填充NaN值,向后同理

# 在df 的e 这一列上操作,默认下按行操作,向前填充数据,即取e列中最近的一个不为NaN值来填充接下去的NaN值
df["e"].fillna(method = 'ffill',inplace=True)
# 原理同上,只是取e列中最近的一个不为NaN值并且它的上一个数值是NaN值 的值来填充接下去的NaN值
df["e"].fillna(method = 'bfill',inplace=True)
# 对 gake 行操作,axis=0按行操作,取该行中最先出现的一个不为NaN值填充接下去的NaN值
df.loc["gake"].fillna(method = 'ffill',inplace=True, axis = 0)
# 原理同上,只是变成了向后取值
df.loc["gake"].fillna(method = 'bfill',inplace=True, axis = 0)
# 对整个df 正常,按列操作,取最先出现NaN值的前一列数值,用来填充接下去出现NaN值的全部列
df.fillna(method = 'ffill',inplace=True, axis = 1)

也可以通过重新赋值的赋值来填充NaN值,即将一个series 赋值给df 的某一列 来达到删除NaN值的目的。

interpolate()

利用插值函数interpolate()对列向的数据进行填值。实现插值填充数据,那么要求这列上必须得有一些数据才可以,至少2个,会对起点和终点间的NaN进行插值。
示例:

val = np.arange(10, 38).reshape(7, 4)
col = list("abcd")
idx = "cake make fake sake wake lake take".split()
df = pd.DataFrame(val, columns = col, index = idx)
df["e"] = np.nan
df.at["fake", "e"] = 100
df.at["lake", "e"] = 600
df["f"] = np.nan
df.loc["gake"] = np.nan 
df.at["gake", "c"] = 700
df["e"].interpolate(inplace=True)
df["f"].interpolate(inplace=True)
"""
       a   b    c   d    e   f
cake  10  11   12  13  NaN NaN
make  14  15   16  17  NaN NaN
fake  18  19   20  21  100 NaN
sake  22  23   24  25  NaN NaN
wake  26  27   28  29  NaN NaN
lake  30  31   32  33  600 NaN
take  34  35   36  37  NaN NaN
gake NaN NaN  700 NaN  NaN NaN    df
       a   b    c   d           e   f
cake  10  11   12  13         NaN NaN
make  14  15   16  17         NaN NaN
fake  18  19   20  21  100.000000 NaN
sake  22  23   24  25  266.666667 NaN
wake  26  27   28  29  433.333333 NaN
lake  30  31   32  33  600.000000 NaN
take  34  35   36  37  600.000000 NaN
gake NaN NaN  700 NaN  600.000000 NaN    df.interpolate()
"""

可以看出,当待填充的列或行符合条件时,会从最近的那个非NaN值开始将之后的位置全部填充,填充的数值为列上保留数据的最大值最小值之间的浮点数值。

3. 删除重复数据

对于数据源中的重复数据,一般来讲没有什么意义,所以一般情况下都会进行删除操作。

duplicated()

duplicated 方法可以返回重复数据的分布情况,以布尔值显示。

col = ["apple", "pearl", "watermelon"] * 4
pri = [2.50, 3.00, 2.75] * 4
df = pd.DataFrame({
   "fruit": col, "price" : pri})
df.duplicated()
# drop_duplicates 方法用于删除
df.drop_duplicates()
df.drop_duplicated(["page"], keep="first", inplace=True)

drop_duplicated()

删除重复值,可以指定inplace 是否在原对象上直接操作,keep= last first false 等 默认first保留第一次出现的重复数据,last同时保留最后一次出现的重复数据,false 不保留

使用如上。

4. 数据匹配替换

简单数据删除填充有时并不能满足需求,因此需要数据进行匹配替换满足更进一步的需求。

map()

map函数可以将某列数据映射成其它数据

oSeries = pd.Series(["a", "b", "c"], index = [2,3,1])
iSeries = pd.Series([100,200, 300], index = ["c","b","a"])
oSeries.map(iSeries)
"""
2    a
3    b
1    c
dtype: object    oSeries
c    100
b    200
a    300
dtype: int64    iSeries
2    300
3    200
1    100
dtype: int64    oSeries.map(iSeries)
"""
# 将oSeries 的value 替换成了 iSeries 的value

map 一般对index 和 series 等使用。

replace()

将数据替换成其他数据,可以一对一的替换也可一堆多的替换数据。

# 对series 而言,简单的一对一替换
ss = pd.Series(["a", "b", "c"], index = [2,3,1])
ss.replace("b", "hello", inplace = True)
# 同样可以多对多替换
ss.replace(["c", "a"], ["hello", "world"], inplace = True)
# 字典形式传参也可以,key是待替换的值,value是替换的值
ss.replace({
   "c":"hello", "a" : "world"}, inplace = True)


# 对dataframe 而言,使用replace 稍有不同
idx = [1,3,2,4]
val = {
   'name' : "hello the cruel world".split(),
       'growth' : [100, 125, 150, 200]}
df = pd.DataFrame(val, idx)
# 第一个以字典形式确定要替换被的元素,key为元素所在行,value为待替换数值,第二个参数是替换成的值
df.replace({
   "name" : "the"}, "THE", inplace = True)

5. apply() 方法使用

replace、dropna、fillna函数要么针对NaN的某行或某列或某个,这些函数的作用有限,本章介绍的apply等函数可以针对整个Series或DataFrame的各个值进行相应的数据的处理

对series 使用apply

# 对series 使用apply ,会将series 中的每个元素执行操作
s = pd.Series(np.arange(2,6))
s.apply(lambda x : 2 * x)

对dataframe 使用apply

# 对df 使用apply,都是按行或按列操作,不能保证对每一个元素进行操作
df = pd.DataFrame(val, index=idx, columns=col)
# 按行操作,对数据求和
print(type(df.apply(lambda col: col.sum(), axis='rows')))
# 按列操作,对数据求和
print(df.apply(lambda row: row.sum(), axis='columns'))
# df["hello x the"] = df.apply(lambda row: row.hello * row.the, axis=1)

df 中的applymap()

df 中使用applymap 可以对df 中的每一个元素进行操作

val = np.arange(10, 60).reshape(10, 5)
idx = np.arange(10, 20)
col = list('abcde')
df = pd.DataFrame(val, index = idx, columns = col)
# df 中的每一个元素都会被加3
print(df.applymap(lambda x : x + 3))

pandas 数据拼接

1. concat() 拼接方法

对series 操作

s1 = pd.Series(np.arange(2,6))
s2 = pd.Series(np.arange(8,12))
# 后一个series 接在前一个series后面
ss = pd.concat([s1, s2])

对dataframe 操作

# 两个DataFrame的拼接 1). label和columns均相同的情况下:
col = "hello the cruel world".split()
idx = ["a", "b", "c", "d"]
val1 = np.arange(16).reshape(4, 4)
val2 = np.arange(20, 36).reshape(4, 4)
df1 = pd.DataFrame(val1, index = idx, columns = col)
df2 = pd.DataFrame(val2, index = idx, columns = col)
# 在列标 相同的情况下,就是后一个df 接在前一个df 后面
df12 = pd.concat([df1, df2])

当然,列标和行标不一定是对应的,这个时候两DataFrame未匹配上的label或columns下的值为NaN

concat 函数 同样的可以指定是按行操作还是按列操作。

指定拼接的轴,默认是列方向的拼接数据,可以指定concat 的形参axis为行上的拼接数据。

2. concat 的内外连接

concat 的内外连接,就是 join 参数的指定,为 inner 时为内连接,为outer 时外连接。

col1 = "hello the cruel world".split()
col2 = "hello the nice world".split()
idx1 = ["a", "b", "c", "d"]
idx2 = ["a", "b", "d", "e"]
val1 = np.arange(16).reshape(4, 4)
val2 = np.arange(20, 36).reshape(4, 4)
df1 = pd.DataFrame(val1, index = idx1, columns = col1)#
df2 = pd.DataFrame(val2, index = idx2, columns = col2)
# "***outer join"
pd.concat([df1, df2], join = "outer")
# "***inner join"
pd.concat([df1, df2], join = "inner")
# concat 的内外连接 实际上就是对两个df 求交集还是并集的选择
# 外连接就是并集,内连接就是交集

3. merge() 方法

merge函数可以真正实现数据库的内外连接,且外连接还可以有左右连接的特性。

补充:

内连接,对两张有关联的表进行内连接操作,结果表会是两张表的交集,例如A表和B表,如果是A 内连接(inner join)B表,结果表是以A为基准,在B中找寻A匹配的行,不匹配则舍弃,B内连接A同理。
外连接,分左外连接,右外连接,全连接,左外连接是左表上的所有行匹配右表,正常能匹配上的取B表的值,不能的取空值,右外连接同理,全连接则是取左并上右表的的所有行,没能匹配上的用空值填充。

merge 默认是内连接

# 默认情况下,merge函数是内连接
print(course.merge(choose))
# 变换两张表的位置,得到的结果并不一样
print(choose.merge(course))

merge可以进行左外连接,右外连接,全连接。

# 通过指定how 参数可以进行全连接,course表并上choose表得出结果
print(course.merge(choose, how = "outer"))
# 同理,choose表并上course表得出结果
print(choose.merge(course, how = "outer"))

# merge进行左右外连接
# course表左外连接choose表,结果保留course 的全部行及列,和choose表进行匹配,不匹配以空值替代
print course.merge(choose, how = "left")
# course 表右外连接choose表,结果保留choose表的全部行列,和course表进行匹配,同时course表的数据会显示在choose表前
print course.merge(choose, how = "right")
# choose表左外连接course,和course表右外连接choose表结果一致,但choose表的数据显示在前
print choose.merge(course, how = "left")
# 和course 左外连接 choose结果一样,但每列数据的排列会有区别,因为结果表会先显示左表的结果
print choose.merge(course, how = "right")

pandas 数据分组

1. groupby 方法

DataFrame数据对象经groupby()之后有ngroups和groups等属性,其本质是DataFrame类的子类DataFrameGroupBy的实例对象。ngroups反应的是分组的个数,而groups类似dict结构,key是分组的index或label,value则为index或label所对应的分组数据。size函数则是可以返回所有分组的字节大小。count函数可以统计分组后各列数据项个数。get_group函数可以返回指定组的数据信息。而discribe函数可以返回分组后的数据的统计数据。

简单的按单列分组

# 按单列进行分组
dg =  df0.groupby("fruit")
# 打印查看按fruit分组后的每组组名,及详细信息
for n, g in dg:
    print "group_name:", n, "\n|",g,"|" 
# 查看组名和 每组的数据信息
for n,_ in dg:
    print "group_name:", n, "\n|",dg.get_group(n),"|" 
# 查看分组后的统计数据
print dg.describe()

也支持多列分组

dg1 =  df0.groupby(["fruit", "supplier"])
for n, g in dg1:
    print "multiGroup on:", n, "\n|",g ,"|"

2. aggregate 聚合

在使用groupby 分组完成后,借助aggregate函数可以 经过分组后 每组进行操作。

agg的形参是一个函数会对分组后每列都应用这个函数。

# 分组后对每组数据求平均值
print dg1.agg(np.mean)

也可以应用多个函数

# 以列表的形式传入参数即可,会对每组都执行全部的聚合函数
print dg1.agg([np.mean, np.std, np.min, np.sum])

可以对每列数组进行不同的聚合操作

# 传入字典,key为列名,value为要执行的聚合函数
print dg1.agg({
   "price" : np.mean, "supplier" : np.max})

3. transform() 方法

可以作用于groupby之后的每个组的所有数据,之前的aggregate函数只能用于分组后组的每列数据。

import pandas as pd
import numpy as np
idx = [101,101,101,102,102,102,103,103,103]
idx += [101,102,103] * 3
name = ["apple","pearl","orange", "apple","pearl","orange","apple","pearl","orange"]
name += ["apple"] * 3 + ["pearl"] * 3 + ["orange"] * 3
price = [4.1,5.3,6.3,4.20,5.4,6.0,4.5,5.5,6.8]
price += [4] * 3 + [5] * 3 + [6] * 3
df0 = pd.DataFrame({
    "fruit": name, "price" : price, "supplier" :idx})
dg1 =  df0.groupby(["fruit"])
def f1(x):
    return x + 1
def f2(x):
    return x + 100
# 选择某一列,调用transform方法,对每个数据都执行f1函数
print dg1["price"].transform(f1)[:3]
print dg1["supplier"].transform(f2)[:3]
# 直接调用对每个元素都执行f2 函数
print dg1.transform(f2)[:3]

# [:3] 是只打印前三个元素的意思

pandas 时间序列

时间序列数据在金融、经济、神经科学、物理学里都是一种重要的结构化的数据表现形式。
pandas 最基本的时间序列类型就是以时间戳(TimeStamp)为 index 元素的 Series 类型。Python和Pandas里提供大量的内建工具、模块可以用来创建时间序列类型的数据。

1. datetime 模块

Python的datetime标准模块下的

date子类可以创建日期时间序列的数据

time子类可创建小时分时间数据

datetime子类则可以描述日期小时分数据

import datetime
# 日期小时分秒 日期数据
cur = datetime.datetime(2018,12,30, 15,30,59)
print(cur,type(cur))
# 获得日类类型的时间数据
d = datetime.date(2018,12,30)
print(d)
# 获得小时分数据
t = datetime.time(12, 30, 5)
print(t)

datetime的timedelta模块给出时间间隔(差)

借助timedelta 可以定义时间时间间隔

# 设置一个日期
cur0 = datetime.datetime(2018,12,30, 15,30,59)
# 获取 从 cur0 加上一天的时间间隔
cur1 = cur0 + datetime.timedelta(days = 1)
# cur0 加上 10分钟的时间间隔
cur2 = cur0 + datetime.timedelta(minutes = 10)
# cur0 加上 29分钟 1秒的时间间隔
cur3 = cur0 + datetime.timedelta(minutes = 29,seconds = 1)

用datetime数据创建time series时间序列数据。意思就是用datetime创建的时间作为index。.

from datetime import datetime, timedelta
import numpy as np
import pandas as pd
b = datetime(2018,12,16, 17,30,55)
vi = np.random.randn(60)
ind = []
for x in range(60):
    bi = b + timedelta(minutes = x)
    ind.append(bi)
# series 的index 为 一串时间数据
ts = pd.Series(vi, index = ind)
# 显示前5条数据
print ts[:5]
目录
相关文章
|
4月前
|
数据可视化 数据挖掘 数据处理
进阶 pandas DataFrame:挖掘高级数据处理技巧
【5月更文挑战第19天】本文介绍了Pandas DataFrame的高级使用技巧,包括数据重塑(如`pivot`和`melt`)、字符串处理(如提取和替换)、日期时间处理(如解析和时间序列操作)、合并与连接(如`merge`和`concat`),以及使用`apply()`应用自定义函数。这些技巧能提升数据处理效率,适用于复杂数据分析任务。推荐进一步学习和探索Pandas的高级功能。
|
4月前
|
数据处理 索引 Python
使用pandas的merge()和join()函数进行数据处理
使用pandas的merge()和join()函数进行数据处理
81 2
|
29天前
|
数据采集 数据挖掘 数据处理
解锁Python数据分析新技能!Pandas实战学习,让你的数据处理能力瞬间飙升!
【8月更文挑战第22天】Python中的Pandas库简化了数据分析工作。本文通过分析一个金融公司的投资数据文件“investment_data.csv”,介绍了Pandas的基础及高级功能。首先读取并检查数据,包括显示前几行、列名、形状和数据类型。随后进行数据清洗,移除缺失值与重复项。接着转换日期格式,并计算投资收益。最后通过分组计算平均投资回报率,展示了Pandas在数据处理与分析中的强大能力。
31 0
|
2月前
|
机器学习/深度学习 数据采集 大数据
驾驭大数据洪流:Pandas与NumPy在高效数据处理与机器学习中的核心作用
【7月更文挑战第13天】在大数据时代,Pandas与NumPy是Python数据分析的核心,用于处理复杂数据集。在一个电商销售数据案例中,首先使用Pandas的`read_csv`加载CSV数据,通过`head`和`describe`进行初步探索。接着,数据清洗涉及填充缺失值和删除异常数据。然后,利用`groupby`和`aggregate`分析销售趋势,并用Matplotlib可视化结果。在机器学习预处理阶段,借助NumPy进行数组操作,如特征缩放。Pandas的数据操作便捷性与NumPy的数值计算效率,共同助力高效的数据分析和建模。
54 3
|
2月前
|
机器学习/深度学习 数据采集 数据处理
重构数据处理流程:Pandas与NumPy高级特性在机器学习前的优化
【7月更文挑战第14天】在数据科学中,Pandas和NumPy是数据处理的关键,用于清洗、转换和计算。用`pip install pandas numpy`安装后,Pandas的`read_csv`读取数据,`fillna`处理缺失值,`drop`删除列。Pandas的`apply`、`groupby`和`merge`执行复杂转换。NumPy加速数值计算,如`square`进行向量化操作,`dot`做矩阵乘法。结合两者优化数据预处理,提升模型训练效率和效果。
37 1
|
2月前
|
数据采集 机器学习/深度学习 数据处理
从基础到卓越:Pandas与NumPy在复杂数据处理中的实战策略
【7月更文挑战第14天】Pandas与NumPy在数据科学中的核心应用:**加载数据(如`read_csv`)、探索(`head()`, `info()`, `describe()`)、数据清洗(`fillna`, `dropna`, `replace`, `apply`)、数值计算(借助NumPy的`ndarray`)、分组聚合(`groupby`与聚合函数)、窗口函数(如`rolling`)和数据筛选排序(布尔索引,`query`,`sort_values`)。通过这些工具,实现从数据预处理到复杂分析的高效处理。
37 0
|
2月前
|
存储 数据可视化 数据处理
`geopandas`是一个开源项目,它为Python提供了地理空间数据处理的能力。它基于`pandas`库,并扩展了其对地理空间数据(如点、线、多边形等)的支持。`GeoDataFrame`是`geopandas`中的核心数据结构,它类似于`pandas`的`DataFrame`,但包含了一个额外的地理列(通常是`geometry`列),用于存储地理空间数据。
`geopandas`是一个开源项目,它为Python提供了地理空间数据处理的能力。它基于`pandas`库,并扩展了其对地理空间数据(如点、线、多边形等)的支持。`GeoDataFrame`是`geopandas`中的核心数据结构,它类似于`pandas`的`DataFrame`,但包含了一个额外的地理列(通常是`geometry`列),用于存储地理空间数据。
|
4月前
|
数据挖掘 数据处理 Python
【Python DataFrame 专栏】深入探索 pandas DataFrame:高级数据处理技巧
【5月更文挑战第19天】在 Python 数据分析中,pandas DataFrame 是核心工具。本文介绍了几个高级技巧:1) 横向合并 DataFrame;2) 数据分组与聚合;3) 处理缺失值;4) 数据重塑;5) 条件筛选;6) 使用函数处理数据。掌握这些技巧能提升数据处理效率和分析深度,助你更好地发掘数据价值。
36 1
【Python DataFrame 专栏】深入探索 pandas DataFrame:高级数据处理技巧
|
3月前
|
存储 数据挖掘 数据处理
19. Python 数据处理之 Pandas
19. Python 数据处理之 Pandas
40 1
|
3月前
|
数据采集 安全 数据处理
Python采集数据处理:利用Pandas进行组排序和筛选
使用Python的Pandas库,结合亿牛云代理和多线程技术,提升网络爬虫数据处理效率。通过代理IP避免封锁,多线程并发采集,示例代码展示数据分组、排序、筛选及代理IP配置和线程管理。
Python采集数据处理:利用Pandas进行组排序和筛选