Python数据分析利器:Pandas实战技巧与高级应用
本文详细介绍了Pandas在数据分析中的应用,包括基础数据结构Series和DataFrame的使用,以及如何通过Pandas进行数据导入、清洗、处理、统计和输出。通过实际代码示例,展示了如何创建DataFrame、获取数据大小、选择数据、创建新列、删除重复行等操作。同时,文章还探讨了如何使用Pandas进行数据格式转换、重命名列、处理空值、应用统计函数,以及如何使用SQL语句与Pandas结合进
目录
Pandas简介
在数据分析工作中,Pandas 的使用频率是很高的,一方面是因为 Pandas 提供的基础数据结构 DataFrame 与 json 的契合度很高,转换起来就很方便。另一方面,如果我们日常的数据清理工作不是很复杂的话,你通常用几句 Pandas 代码就可以对数据进行规整。Pandas 可以说是基NumPy 构建的含有更高级数据结构和分析能力的工具包。
数据结构:Series 和 DataFrame
Series 和 DataFrame 这两个核心数据结构,他们分别代表着一维的序 列和二维的表结构。基于这两种数据结构,Pandas 可以对数据进行导入、清洗、处理、统计和输出。
Series 是个定长的字典序列。说是定长是因为在存储的时候,相当于两个 ndarray,这也是和字典结构最大的不同。因为在字典的结构里,元素的个数是不固定的。
Series有两个基本属性:index 和 values。在 Series 结构中,index 默认是 0,1,2,……递增的整数序列,当然我们也可以自己来指定索引,比如 index=[‘a’, ‘b’, ‘c’, ‘d’]。
DataFrame 类型数据结构类似数据库表。它包括了行索引和列索引,我们可以将 DataFrame 看成是由相同索引的 Series 组成的字典类型。
Pandas常用统计函数
实际应用
示例一
从表中创建 DataFrame
import pandas as pd
def createDataframe(student_data: List[List[int]]) -> pd.DataFrame:
column_names = ["student_id", "age"]
result_dataframe = pd.DataFrame(student_data, columns=column_names)
return result_dataframe
获取 DataFrame 的大小
def getDataframeSize(players: pd.DataFrame) -> List[int]:
return [players.shape[0], players.shape[1]]
显示前三行
def selectFirstRows(employees: pd.DataFrame) -> pd.DataFrame:
return employees.head(3)
数据选取
def selectData(students: pd.DataFrame) -> pd.DataFrame:
return students.loc[students["student_id"] == 101, ["name", "age"]]
关键概念:
- loc 属性: 从 DataFrame 中选择数据的主要方法之一。它是基于标签的,这意味着您必须指定行或列的名称才能选择数据。loc 是基于标签的。如果您希望使用基于整数的位置,请改用 iloc。
- boolean 遮罩: 一系列 True/False 值,用于根据特定条件从另一个数据结构(如列表、数组或 DataFrame)中筛选或选择元素。
创建、修改、重命名列
def createBonusColumn(employees: pd.DataFrame) -> pd.DataFrame:
employees['bonus'] = employees['salary'] * 2
return employees
def modifySalaryColumn(employees: pd.DataFrame) -> pd.DataFrame:
employees['salary'] = employees['salary'] * 2
return employees
def renameColumns(students: pd.DataFrame) -> pd.DataFrame:
students = students.rename(
columns={
"id": "student_id",
"first": "first_name",
"last": "last_name",
"age": "age_in_years",
}
)
return students
删去重复的行
def dropDuplicateEmails(customers: pd.DataFrame) -> pd.DataFrame:
#基于电子邮件删除重复行
customers.drop_duplicates(subset='email', keep='first', inplace=True)
return customers
drop_duplicates
函数是 pandas 库中 DataFrame 对象的方法。它的目的是删除重复的行,您可以指定被视为重复的行所基于的条件。
drop_duplicates 函数参数定义:
1. subset:此参数标识重复行时要考虑的列标签或标签序列。如果未提供,它将处理DataFrame 中的所有列。
2. keep:此参数确定要保留的重复行。
- 'first': (默认) 删除除第一个匹配项以外的重复项。
- 'last': 删除除最后一个匹配项之外的重复项。
- False: 删除所有重复项。
3. inplace: 如果设置为 True,则直接对对象进行更改,而不返回新的对象。如果设置为 False(默认),则返回丢弃重复的新对象。
删出为NaN的行
def dropMissingData(students: pd.DataFrame) -> pd.DataFrame:
students.dropna(subset=['name'], inplace=True)
return students
dropna 函数: dropna 函数属于 pandas DataFrame 并且被用来移除缺失的值。在 pandas 中,缺失的数据通常由 NaN(非数字的缩写)值表示,尽管在您的示例中它显示为 None,这也被 pandas 认为是缺失值。
下面是 dropna 函数的一般用法:
DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
dropna 函数参数定义:
- axis: 它可以是 {0 or 'index', 1 or 'columns'}。默认为 0。如果 axis=0,则丢弃包含缺失值的行;如果 axis=1,则丢弃包含缺失值的列。
- how: 确定当我们至少有一个 NA 或全部 NA 时,是否从 DataFrame 中删除行或列。
how='any': 如果存在任何 NA 值,则删除该行或列(默认)。
how='all': 如果所有值都为 NA,则删除该行或列。
- thresh: 需要多少非 NA 值。这是一个整型参数,需要最小数量的非 NA 值才能保留行/列。
- subset: 要考虑的另一个轴上的标签,例如,如果您正在删除行,则这些标签将是要包括的列的列表。当您只想考虑某些列中的 NA 值时,这特别有用。
- inplace: 这是一个布尔值,如果是 True,则对 DataFrame 本身进行更改。请记住,在使用 inplace=True 参数时,您修改的是原始的 DataFrame。如果出于任何原因需要保留原始数据,请避免使用 inplace=True,而是将结果赋给新的 DataFrame。
更改数据类型
def changeDatatype(students: pd.DataFrame) -> pd.DataFrame:
students = students.astype({'grade': int})
return students
填充缺失值
import pandas as pd
def fillMissingValues(products: pd.DataFrame) -> pd.DataFrame:
#将缺少的值(NaN 或 None)替换为 0
products['quantity'].fillna(0, inplace=True)
return products
fillna 函数有几个参数可供您使用,但我们将重点介绍最常用的参数:
- value: 标量,字典,Series 或 DataFrame。用于填充空洞的值(例如 0)。这就是我们在解决方案中使用的。
- method: {‘backfill’, ‘bfill’, ‘pad’, ‘ffill’, None}。用于填充重新索引 Series 中的空洞的方法。默认为 None。
- axis: {0 or ‘index’, 1 or ‘columns’}。沿其填充缺失值的轴。
- inplace: 布尔值。如果为True,则原地填充。注意:这将修改此对象上的任何其他视图。默认值为 False。
归并(merge)
使用 pd.merge() 函数,能将多个 DataFrame 归并在一起,它的合并方式类似合并 SQL 数据表的方式。归并操作的基本语法:
pd.merge(left, right, how='inner', on='Key')
- left 参数代表放在左侧的 DataFrame
- right 参数代表放在右边的 DataFrame
- how='inner' 指的是当左右两个 DataFrame 中存在不重合的 Key 时,取结果的方式:默认:inner 内连接,取交集”,outer 外连接,取并集,并用nan填充”,left 左连接, 左侧取全部,右侧取部分”,right 右连接,左侧取部分,右侧取全部”
- on='Key' 代表需要合并的键值所在的列,最后整个表格会以该列为准进行归并。
对于两个都含有 key 列的 DataFrame,我们可以这样归并:
也可以传入多个 on 参数,这样就能按多个键值进行归并:
结果中的三行代表了两个DataFrame之间可能的匹配组合:
- 第一行出现是因为
left
DataFrame中的'key1'和'key2'均为'K0',与right
DataFrame中的第一行匹配。- 第二行和第三行出现是因为
left
DataFrame中的'key1'为'K1'和'key2'为'K0',在right
DataFrame中找到了两个匹配项,即'key1'和'key2'都是'K1'和'K0'的两行。因此,每个匹配都会在结果DataFrame中创建一行,这就是为什么有三行结果的原因。每行结果都是两个DataFrame中匹配行的组合。
连接(concat)
有点类似SQL的union all
import pandas as pd
def concatenateTables(df1: pd.DataFrame, df2: pd.DataFrame) -> pd.DataFrame:
return pd.concat([df1, df2], axis=0)
pd.concat():pandas 内部的一个方便的函数,用于垂直(按行)或水平(按列)连接 DataFrame。
- objs 参数是一个要串联的 Series 或 DataFrame 对象的序列或映射。
- axis 参数决定连接的方向:
axis=0 设置为缺省值,这意味着它将垂直(按行)连接 DataFrame。
axis=1 将水平连接 DataFrame(按列)。
透视(pivot)
有点类似SQL的行转列
def pivotTable(weather: pd.DataFrame) -> pd.DataFrame:
ans = weather.pivot(index='month', columns='city', values='temperature')
return ans
pivot 函数: 在 pandas 中 pivot 函数被用来基于列的值重塑数据并且在外部得到一个新的 DataFrame。pivot 采用我们将使用的以下参数:
- index: 确定新 DataFrame 中的行。
- columns: 确定新 DataFrame 中的列。
- values: 指定重塑表格时要使用的值。
融合(melt)
有点类似SQL的列转行
def meltTable(report: pd.DataFrame) -> pd.DataFrame:
report = report.melt(
id_vars=["product"],
value_vars=["quarter_1", "quarter_2", "quarter_3", "quarter_4"],
var_name="quarter",
value_name="sales",
)
return report
示例二
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)
# 这个例子中,x1 中的 index 采用的是默认值,x2 中 index 进行了指定。我们也可以采用
# 字典的方式来创建 Series,比如
d = {'a':1, 'b':2, 'c':3, 'd':4}
x3 = Series(d)
print (x3)
data = {'Chinese': [66, 95, 93, 90,80],'English': [65, 85, 92, 88, 90],'Math': [30, 98,96,77,90]}
df1= DataFrame(data)
df2 = DataFrame(data, index=['ZhangFei', 'GuanYu', 'ZhaoYun', 'HuangZhong', 'DianWei'])
print (df1)
print (df2)
#Pandas 允许直接从 xlsx,csv 等文件中导入数据,也可以输出到 xlsx, csv 等文件,非常方便。
# score = DataFrame(pd.read_excel('data.xlsx'))
# score.to_excel('data1.xlsx')
# print (score)
#更改数据格式
#df2['Chinese'].astype('str')
# df2['Chinese'].astype(np.int64)
# 有时候我们先把格式转成了 str 类型,是为了方便对数据进行操作,这时想要删除数据间的
# 空格,我们就可以使用 strip 函数:
# 删除左右两边空格
df2['Chinese']=df2['Chinese'].astype('str').map(str.strip)
# 删除左边空格
df2['Chinese']=df2['Chinese'].astype('str').map(str.lstrip)
# 删除右边空格
df2['Chinese']=df2['Chinese'].astype('str').map(str.rstrip)
# 全部大写
df2.columns = df2.columns.str.upper()
# 全部小写
df2.columns = df2.columns.str.lower()
# 首字母大写
df2.columns = df2.columns.str.title()
#把"张飞"这行删掉。
df2 = df2.drop(index=['ZhangFei'])
#把"语文"这列删掉
# df2 = df2.drop(columns=['Chinese'])
# 如果你想对 DataFrame 中的 columns 进行重命名,可以直接使用
# rename(columns=new_names, inplace=True) 函数,比如我把列名 Chinese 改成
# YuWen,English 改成 YingYu。
df2.rename(columns={'Chinese': 'YuWen', 'English': 'Yingyu'}, inplace = True)
# 去除重复行
df2 = df2.drop_duplicates()
#如果我们想看下哪个地方存在空值 NaN,可以针对数据表 df 进行
df2.isnull()
#如果我想知道哪列存在空值,可以使用
df3=df2.isnull().any()
print(df3)
df2['YuWen'] = df2['YuWen'].apply(str.upper)
def double_df(x):
return 2*x
df2['YuWen'] = df2['YuWen'].apply(double_df)
# 我们也可以定义更复杂的函数,比如对于 DataFrame,我们新增两列,其中’new1’列
# 是“语文”和“英语”成绩之和的 m 倍,'new2’列是“语文”和“英语”成绩之和的 n
# 倍,我们可以这样写:
def plus(df,n,m):
df['new1'] = (df['Math']+df['Yingyu']) * m
df['new2'] = (df['Math']+df['Yingyu']) * n
return df
df2 = df2.apply(plus,axis=1,args=(2,3,))
print(df2)
# 其中 axis=1 代表按照列为轴进行操作,axis=0 代表按照行为轴进行操作,args 是传递的
# 两个参数,即 n=2, m=3,在 plus 函数中使用到了 n 和 m,从而生成新的 df。
# describe() 函数,统计函数千千万,describe() 函数最简便。它是个统计大
# 礼包,可以快速让我们对数据有个全面的了解。下面我直接使用 df1.descirbe()
df1 = DataFrame({'name':['ZhangFei', 'GuanYu', 'a', 'b', 'c'], 'data1':range(5)})
print (df1.describe())
df1 = DataFrame({'name':['ZhangFei', 'GuanYu', 'a', 'b', 'c'], 'data1':range(5)})
df2 = DataFrame({'name':['ZhangFei', 'GuanYu', 'A', 'B', 'C'], 'data2':range(5)})
#基于 name 这列进行连接。
df3 = pd.merge(df1, df2, on='name')
# inner 内链接是 merge 合并的默认情况,inner 内连接其实也就是键的交集,在这里 df1,
# df2 相同的键是 name,所以是基于 name 字段做的连接:
df3 = pd.merge(df1, df2, how='inner')
df3 = pd.merge(df1, df2, how='left')
df3 = pd.merge(df1, df2, how='right')
df3 = pd.merge(df1, df2, how='outer')
# Pandas 的 DataFrame 数据类型可以让我们像处理数据表一样进行操作,比如数据表的增
# 删改查,都可以用 Pandas 工具来完成。不过也会有很多人记不住这些 Pandas 的命令,
# 相比之下还是用 SQL 语句更熟练,用 SQL 对数据表进行操作是最方便的,它的语句描述形
# 式更接近我们的自然语言。
# 事实上,在 Python 里可以直接使用 SQL 语句来操作 Pandas。
from pandasql import sqldf, load_meat, load_births
df1 = DataFrame({'name':['ZhangFei', 'GuanYu', 'a', 'b', 'c'], 'data1':range(5)})
pysqldf = lambda sql: sqldf(sql, globals())
sql = "select * from df1 where name ='ZhangFei'"
print (pysqldf(sql))
示例三
import boto3
import pandas as pd
client = boto3.client(
"s3",
endpoint_url="https://xxx",
aws_access_key_id="aws_access_key_id",
aws_secret_access_key="aws_secret_access_key",
)
def get_part_from_path(path):
table = path.split("/")[2]
return table
def get_endswith(path):
ends = path[-1]
return ends
def stat_aws(bucket, prefix):
marker = ""
data = []
while True:
res = client.list_objects(
Bucket=bucket, Prefix=prefix, Marker=marker,
)
marker = res.get("NextMarker")
# Key,LastModified,ETag,Size,StorageClass,Owner
data += res.get("Contents", [])
if marker is None:
break
df = pd.DataFrame(data)
return df
bucket_prefix = {
'bucket_name': ['hive/ao_dodo/'],
}
if __name__ == '__main__':
pd.set_option('display.unicode.ambiguous_as_wide', True) #处理数据的列标题与数据无法对齐的情况
pd.set_option('display.unicode.east_asian_width', True) #无法对齐主要是因为列标题是中文
pd.set_option('display.max_columns', None) #显示所有列
#pd.set_option('display.max_rows', None) #显示所有行
pd.set_option('display.width', 300) #数据显示总宽度
for bucket in bucket_prefix:
for prefix in bucket_prefix[bucket]:
df = stat_aws(bucket, prefix)
print(df)
# inplace=False(默认)表示原数组不变,对数据进行修改之后结果给新的数组。
# inplace=True表示直接在原数组上对数据进行修改。
# 删掉key列中所有以'/'结尾的行
df.drop(df.index[(df['Key'].apply(get_endswith) == '/')], inplace=True)
print(df)
df["cnt"] = 1
df["table_name"] = df["Key"].apply(get_part_from_path)
print(df)
#df.reset_index() # 会将原来的索引index作为新的一列
df_res = df.groupby("table_name")["Size","cnt"].sum().reset_index()
print(df_res)
df_res = df.groupby('table_name').agg(
{'Size': ['sum'], 'cnt': ['sum'], 'LastModified': ['max']}).reset_index()
print(df_res)
df_res['bucket'] = bucket
df_res['prefix'] = prefix
df_res["size_gb"] = df_res["Size"] / 1024 ** 3
df_res["all_size_prefix_gb"] = df_res["size_gb"].sum()
df_res.columns = pd.Series(
['table_name', 'Size', 'cnt', 'LastModified', 'bucket', 'prefix', 'size_gb', 'all_size_prefix_gb'])
print(df_res)
df_res.drop(index=[0], inplace=True)
print(df_res)
break
print('cosSize')
print(df)
print(df_res)
拓展阅读
Python pandas数据分析中常用方法_青盏的博客-CSDN博客
更多推荐
所有评论(0)