目录

Pandas简介

数据结构:Series 和 DataFrame

Pandas常用统计函数 

实际应用

示例一

从表中创建 DataFrame

获取 DataFrame 的大小

显示前三行

数据选取

创建、修改、重命名列

删去重复的行

删出为NaN的行

更改数据类型 

填充缺失值

连接 (union all)

透视 (行转列)

融合(列转行)

示例二

示例三

拓展阅读 


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之间可能的匹配组合:

  1. 第一行出现是因为left DataFrame中的'key1'和'key2'均为'K0',与right DataFrame中的第一行匹配。
  2. 第二行和第三行出现是因为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) 

拓展阅读 

像Excel一样使用python进行数据分析

Python pandas数据分析中常用方法_青盏的博客-CSDN博客

30 天 Pandas 挑战 - 学习计划 - 力扣(LeetCode)全球极客挚爱的技术成长平台

Pandas 入门 15 题 - 学习计划 - 力扣(LeetCode)全球极客挚爱的技术成长平台 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐