Pandas

Pandas

Yiuhang Chan

Pandas简介

文件的读取与数据创建

读取CSV文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import pandas as pd

# 读取CSV文件(基本)
df = pd.read_csv(
"./路径/文件.csv",
encoding='utf-8', # 指定文件编码
index_col=None, # 指定索引列,None表示不将任何列用作索引
sep=',', # 指定字段分隔符,逗号(,)是默认值
usecols=None, # 指定要读取的列,None表示读取所有列
names=None # 指定列名,None表示使用文件第一行作为列名
)

# 读取TSV文件(制表符分隔的文件)
df_tsv = pd.read_csv(
"./路径/文件.tsv",
sep='\t' # 制表符作为字段分隔符
)

# 读取文本文件,指定分隔符,列名和没有标题行
df_txt = pd.read_csv(
'./路径/文件.txt',
sep='\t', # 制表符作为字段分隔符
header=0, # 指定标题所在行的索引,0表示第一行
names=['字段1', '字段2'] # 指定列名
)

存储CSV文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 存储为CSV文件(基本)
df.to_csv("./路径/文件.csv")

# 存储为TSV文件(制表符分隔的文件)
df.to_csv(
"./路径/文件.tsv",
sep='\t', # 指定制表符作为字段分隔符
index=False # 不保存索引列到文件
)

# 存储为文本文件,使用制表符作为分隔符,不保存索引
df.to_csv(
"./路径/文件.txt",
sep='\t', # 指定制表符作为字段分隔符
index=False # 不保存索引列到文件
)

对于处理Excel文件、JSON数据、以及与MySQL数据库交互的操作,我们可以整理和规范化代码示例,以提供清晰的指导。

处理Excel文件

读取Excel文件

1
2
3
4
5
6
7
8
9
import pandas as pd

# 读取Excel文件
df = pd.read_excel(
"./路径/文件.xlsx",
engine="openpyxl", # 指定读取引擎,对于.xlsx文件推荐使用'openpyxl'
sheet_name='Sheet1', # 指定工作表名称
header=0 # 指定标题所在行的索引,0表示第一行,None时不将任何行用作列名
)

存储为Excel文件

1
2
3
4
5
6
# 存储DataFrame为Excel文件
df.to_excel(
'./路径/文件.xlsx',
sheet_name='Sheet1', # 指定工作表名称
index=False # 不保存索引列到文件
)

处理JSON数据

读取JSON数据

1
2
3
4
5
6
# 从文件读取JSON数据
df_from_file = pd.read_json('./路径/文件.json')

# 从URL直接读取JSON数据
URL = 'https://example.com/data.json'
df_from_url = pd.read_json(URL)

存储为JSON文件

1
2
# 存储DataFrame为JSON文件
df.to_json('./路径/文件.json')

与MySQL数据库交互

读取MySQL数据库数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import pandas as pd
import mysql.connector

# 连接MySQL数据库
cnx = mysql.connector.connect(
user='用户名',
password='密码',
host='主机地址',
database='数据库名',
charset='utf8'
)

# 使用SQL查询读取数据
query = "SELECT * FROM 表名"
df = pd.read_sql(query, cnx)

# 关闭数据库连接
cnx.close()

存储数据到MySQL数据库

1
2
3
4
5
6
7
8
9
10
11
12
from sqlalchemy import create_engine

# 创建数据库连接引擎
engine = create_engine('mysql+mysqlconnector://用户名:密码@主机地址/数据库名')

# 存储DataFrame到MySQL表中
df.to_sql(
'tablename', # 指定数据库表名
con=engine, # 指定数据库连接
if_exists='replace', # 如果表存在,替换原数据
index=False # 不将DataFrame的索引列存入数据库
)

对于创建Pandas Series的基础知识和示例代码,我们可以进行以下整理以提供清晰、规范的说明和操作步骤。

创建Pandas Series

Series的特点

  • 索引(Index): 每个Series对象都有一个索引,用于标识每个数据点。索引的类型可以是整数、字符串、日期等。如果创建Series时未显式指定索引,Pandas会自动生成一个从0开始的整数索引。
  • 数据类型(Datatype): Series可以包含各种类型的数据(整数、浮点数、字符串等)。Pandas允许Series内的数据类型不同,但通常情况下,为了效率,Series中的数据类型会保持一致。
  • 灵活性: Series支持多种操作,包括数学运算、索引/选择、数据对齐等。

基础语法

创建Series的基础语法如下:

1
pandas.Series(data=None, index=None, dtype=None, name=None, copy=False)

参数说明

  • data: 可以是列表、数组等形式的数据集合。这是Series中存储的主要数据。
  • index: 与数据同长度的索引标签列表。如果未指定,将自动生成从0开始的整数索引。
  • dtype: 数据的类型(如int, float, str等)。如果未指定,dtype将自动推断。
  • name: 为Series指定一个名称,便于理解和输出显示。
  • copy: 是否复制输入数据,默认为False。设置为True可以避免修改原始数据。

创建Series示例

示例1: 使用列表创建Series

1
2
3
4
5
import pandas as pd

data = [1, 2, 3]
series = pd.Series(data)
print(series)

示例2: 使用NumPy数组创建Series

1
2
3
4
5
6
import pandas as pd
import numpy as np

data = np.array([1, 2, 3])
series = pd.Series(data)
print(series)

在这两个示例中,我们创建了包含三个整数的Series对象。由于未指定索引,Pandas自动生成了从0开始的整数索引。这些示例展示了如何从基本的数据结构(列表或NumPy数组)创建Series,并展示了Series的基础属性,如自动索引和数据类型推断。

使用Pandas Series时,索引是一个强大的特性,允许快速访问、修改数据。以下是如何使用索引获取数据和指定索引的整理和示例。

使用索引获取数据

当创建一个Pandas Series对象时,每个元素都会自动分配一个索引。这个索引可以是默认的整数索引,也可以是自定义的索引。

示例1: 使用默认整数索引获取数据

1
2
3
4
5
6
7
8
import pandas as pd

# 创建Series
data = [1, 2, 3]
series = pd.Series(data)

# 使用索引获取数据
print(series[1])

此代码会输出Series中索引为1的元素,即2

指定索引

可以在创建Series时通过index参数自定义索引。

示例2: 使用自定义索引
1
2
3
4
5
6
7
8
import pandas as pd

# 创建Series,指定索引
data = ["Google", "Runoob", "Wiki"]
series = pd.Series(data, index=["x", "y", "z"])

# 输出整个Series
print(series)

输出结果将展示一个Series,其中每个元素都由指定的索引标记:

1
2
3
4
x    Google
y Runoob
z Wiki
dtype: object

在这个例子中,字符串"Google", "Runoob", "Wiki"分别被赋予了自定义索引"x", "y", "z"。通过指定索引,可以提高数据检索的可读性和灵活性。

当创建Pandas Series时,指定索引和使用键值对(类似于字典)作为数据源是两种常见的方法。这提供了灵活的数据结构创建和数据访问方式。下面是对这些概念的整理和示例说明。

示例3: 使用自定义索引访问数据
1
2
3
4
5
6
7
8
import pandas as pd

# 创建Series并指定索引
data = ["Google", "Runoob", "Wiki"]
series = pd.Series(data, index=["x", "y", "z"])

# 使用指定的索引访问数据
print(series["y"])

此代码段会输出索引为"y"的元素,即"Runoob"

使用字典创建Series

当使用字典创建Series时,字典的键自动成为Series的索引,而字典的值成为Series的数据。

示例1: 从字典创建Series

1
2
3
4
5
6
7
8
import pandas as pd

# 使用字典创建Series
sites = {1: "Google", 2: "Runoob", 3: "Wiki"}
series = pd.Series(sites)

# 输出Series
print(series)

这段代码创建了一个Series,其中字典的键(1, 2, 3)自动成为了Series的索引。

示例2: 指定索引过滤数据

如果在使用字典创建Series时还指定了index参数,那么只有在index参数中指定的键会被包含在Series中。

1
2
3
4
5
6
7
8
import pandas as pd

# 使用字典创建Series,并指定索引
sites = {1: "Google", 2: "Runoob", 3: "Wiki"}
series = pd.Series(sites, index=[1, 2])

# 输出Series
print(series)

这段代码将只输出键为1和2的数据项,即"Google""Runoob",因为在创建Series时我们通过index参数指定了只包含这些键。

在处理Pandas Series时,了解如何设置名称、执行基本操作、进行基本运算、以及使用属性和方法是非常重要的。以下是对这些概念的整理和示例说明。

设置Series名称参数

可以在创建Series时通过name参数为Series设置一个名称,这有助于标识Series代表的数据集。

1
2
3
4
5
6
import pandas as pd

# 创建Series并设置名称
sites = {1: "Google", 2: "Runoob", 3: "Wiki"}
myvar = pd.Series(sites, index=[1, 2], name="RUNOOB-Series-TEST")
print(myvar)

基本操作

获取值

1
2
3
4
5
# 使用索引获取单个值
value = myvar[2]

# 使用切片获取多个值
subset = myvar[1:3] # 注意: 切片操作在使用显式索引时是包含结束索引的

遍历Series

1
2
3
# 索引和值的遍历
for index, value in myvar.items():
print(f"Index: {index}, Value: {value}")

基本运算

算术运算

1
2
# 对Series中的每个元素进行乘法运算
result = myvar * 2

过滤

1
2
# 使用条件过滤Series中的元素
filtered_series = myvar[myvar > 2]

应用数学函数

1
2
3
4
import numpy as np

# 对Series中的每个元素应用平方根函数
result = np.sqrt(myvar)

属性和方法

获取索引和值

1
2
3
4
5
# 获取Series的索引
index = myvar.index

# 获取Series的值
values = myvar.values

描述统计

1
2
3
4
5
6
7
# 对DataFrame中的数值列进行描述性统计
data = {'name': ['Alice', 'Bob', 'Charlie', 'David', 'Emily'],
'score': [90, 85, 75, 80, 95],
'age': [20, 25, 30, 35, 40]}
df = pd.DataFrame(data)
stats = df.describe()
print(stats)

获取最大值和最小值的索引

1
2
3
# 获取Series中最大值和最小值的索引
max_index = myvar.idxmax()
min_index = myvar.idxmin()

DataFrame

Pandas的DataFrame是一个二维的、大小可变的、潜在的异构表格数据结构,带有标记的轴(行和列)。理解DataFrame的基础语法和创建方法是使用Pandas进行数据分析和数据处理的基础。

基础语法

创建DataFrame的基础语法如下:

1
pandas.DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)

参数说明

  • data: 接受多种类型的输入,包括但不限于ndarraySeriesmaplistsdict等。这是DataFrame中存储的主要数据。
  • index: 行标签。如果没有指定,就像在Series中一样,Pandas会默认创建从0开始的整数索引。
  • columns: 列标签,默认为RangeIndex (0, 1, 2, …, n)。如果数据输入是字典,则默认列标签是字典键排序后的顺序。
  • dtype: 数据类型。可以为整个DataFrame指定一个统一的数据类型。如果不指定,则会自动推断。
  • copy: 是否复制输入数据,默认为False。如果为True,则复制,这可以避免修改到原始数据。

创建DataFrame示例

通过列表创建DataFrame

1
2
3
4
5
6
7
8
9
10
import pandas as pd

# 创建数据列表
data = [['Google', 10], ['Runoob', 12], ['Wiki', 13]]

# 创建DataFrame
df = pd.DataFrame(data, columns=['Site', 'Age'], dtype=float)

# 打印DataFrame
print(df)

输出结果将是一个DataFrame,包含两列SiteAge,数据类型被设置为浮点数:

1
2
3
4
     Site   Age
0 Google 10.0
1 Runoob 12.0
2 Wiki 13.0

在这个例子中,data是一个列表,其中包含三个子列表,每个子列表代表一行数据。通过columns参数指定了列名为SiteAge,通过dtype参数将所有数值数据类型指定为浮点数。

在Pandas中,DataFrame是用于存储和操作结构化数据的主要数据结构。以下内容整理了DataFrame的创建、基本操作、属性和方法,以及如何从外部数据源创建DataFrame的相关信息。

通过ndarrays或列表的字典创建

1
2
3
4
5
6
import pandas as pd

# 使用字典创建DataFrame
data = {'Site': ['Google', 'Runoob', 'Wiki'], 'Age': [10, 12, 13]}
df = pd.DataFrame(data)
print(df)

输出结果:

1
2
3
4
     Site  Age
0 Google 10
1 Runoob 12
2 Wiki 13

通过字典列表创建

1
2
3
4
# 使用字典列表创建DataFrame
data = [{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}]
df = pd.DataFrame(data)
print(df)

输出结果:

1
2
3
   a   b     c
0 1 2 NaN
1 5 10 20.0

注意:缺失的数据部分为NaN,而非NULL

loc 属性返回指定行的数据

首先,导入Pandas库,并创建一个包含数据的字典,然后将其载入到DataFrame对象中。默认情况下,如果没有指定索引,Pandas会自动创建一个从0开始的整数索引。

1
2
3
4
5
6
7
8
import pandas as pd

data = {
"calories": [420, 380, 390],
"duration": [50, 40, 45]
}

df = pd.DataFrame(data)

返回单行数据

使用loc属性,可以通过指定行索引来返回对应的数据行。此时,返回的结果是一个Pandas Series数据类型。

  • 返回第一行数据:
1
print(df.loc[0])
  • 返回第二行数据:
1
print(df.loc[1])

返回多行数据

loc同样可以用于返回多行数据,通过传递一个包含多个索引的列表作为参数。

  • 返回第一行和第二行数据:
1
print(df.loc[[0, 1]])

使用自定义索引

Pandas允许为DataFrame对象的行设置自定义索引。

1
2
df = pd.DataFrame(data, index = ["day1", "day2", "day3"])
print(df)

使用自定义索引后,可以使用这些索引值来检索数据行。

  • 使用loc属性返回自定义索引对应的某一行:
1
print(df.loc["day2"])

在这个例子中,我们首先设置了自定义索引(”day1”, “day2”, “day3”),然后通过这些索引来检索数据。当使用loc与自定义索引时,指定的索引值必须存在于DataFrame的索引中,否则会引发KeyError

在使用Pandas处理数据时,DataFrame是一个非常核心的数据结构,它允许以表格的形式存储和操作结构化数据。以下是对提供的代码和概念的整理和解释,帮助更好地理解如何使用DataFrame进行基本操作、属性和方法的调用、数据操作技巧,以及如何从外部数据源创建DataFrame

基本操作

获取列

1
name_column = df['Name']

获取行

1
first_row = df.loc[0]

选择多列

1
subset = df[['Name', 'Age']]

过滤行

1
filtered_rows = df[df['Age'] > 30]

属性和方法

获取列名

1
columns = df.columns

获取形状(行数和列数)

1
shape = df.shape

获取索引

1
index = df.index

获取描述统计信息

1
stats = df.describe()

数据操作

添加新列

1
df['Salary'] = [50000, 60000, 70000]

删除列

1
df.drop('City', axis=1, inplace=True)

排序

1
df.sort_values(by='Age', ascending=False, inplace=True)

重命名列

1
df.rename(columns={'Name': 'Full Name'}, inplace=True)

从外部数据源创建 DataFrame

从CSV文件创建

1
df_csv = pd.read_csv('example.csv')

从Excel文件创建

1
df_excel = pd.read_excel('example.xlsx')

从字典列表创建

1
2
data_list = [{'Name': 'Alice', 'Age': 25}, {'Name': 'Bob', 'Age': 30}]
df_from_list = pd.DataFrame(data_list)

注意

  • 灵活性DataFrame可以容纳不同数据类型的列(例如整数、浮点数、字符串等)。
  • 索引:列名和行索引可以是字符串、整数等。Pandas提供了丰富的索引功能,以便于数据选择和操作。
  • 数据操作:可以通过多种方式进行数据选择、过滤、修改和分析,这使得DataFrame非常适合数据清洗、转换、分析和可视化等工作。

案例

缺失率

缺失率是指在数据集中缺失值所占的比例,通常用于数据清洗和预处理阶段,以评估数据的完整性。计算缺失率的基本公式如下:

$$ \text{缺失率 (%)} = \left( \frac{\text{缺失值数量}}{\text{总值数量}} \right) \times 100 $$

其中,

  • 数据集中的缺失值数量是指那些空白或者NULL值的数量。
  • 数据集中的总值数量是指数据集中所有可能的数据点的数量,包括有效值和缺失值。

缺失率可以帮助我们了解数据缺失的严重程度,进而决定如何处理这些缺失值,比如通过删除缺失值、填补缺失值或者采用模型估计等方法。

创建数据表

在这个DataFrame中,包含了几个列:iddatecityagecategory,以及price

1
2
3
4
5
6
7
8
9
10
11
import pandas as pd
import numpy as np

df = pd.DataFrame({
"id": [1001, 1002, 1003, 1004, 1005, 1006],
"date": pd.date_range('20130102', periods=6),
"city": ['Beijing ', 'SH', ' guangzhou ', 'Shenzhen', 'shanghai', 'BEIJING '],
"age": [23, 44, 54, 32, 34, 32],
"category": ['100-A', '100-B', '110-A', '110-C', '210-A', '130-F'],
"price": [1200, np.nan, 2133, 5433, np.nan, 4432]
}, columns=['id', 'date', 'city', 'category', 'age', 'price'])

这段代码首先导入了必要的库:pandasnumpynumpy在这里的用途是提供np.nan来表示缺失值,这在处理真实世界的数据时非常常见。

  • id列包含唯一标识符。
  • date列使用pd.date_range函数生成了一个日期范围。
  • city列包含了一些城市名称,注意这些城市名称前后可能包含空格。
  • age列包含了年龄。
  • category列包含了分类代码。
  • price列包含了价格,使用np.nan表示某些价格未知或缺失。

通过指定columns参数,确保了DataFrame列的顺序按照iddatecitycategoryageprice的顺序排列,即使在字典中的顺序不是这样的。

数据概览

1
print(df)
     id       date         city category  age   price
0  1001 2013-01-02     Beijing     100-A   23  1200.0
1  1002 2013-01-03           SH    100-B   44     NaN
2  1003 2013-01-04   guangzhou     110-A   54  2133.0
3  1004 2013-01-05     Shenzhen    110-C   32  5433.0
4  1005 2013-01-06     shanghai    210-A   34     NaN
5  1006 2013-01-07     BEIJING     130-F   32  4432.0

每列缺失值的数量

1
2
3
# 计算每列缺失值的数量
missing_values_count = df.isnull().sum()
print(missing_values_count)
id          0
date        0
city        0
category    0
age         0
price       2
dtype: int64

信息

1
2
3
4
显示所有的数据
pd.set_option('display.max_rows', None) # 显示所有行
pd.set_option('display.max_columns', None) # 显示所有列
pd.set_option('expand_frame_repr', False) # 不自动换行

缺失率

1
2
3
# 计算缺失率
missing_rate = (missing_values_count / len(df)) * 100
print(missing_rate)
id           0.000000
date         0.000000
city         0.000000
category     0.000000
age          0.000000
price       33.333333
dtype: float64

DataFrame常规操作

修改index、columns

修改DataFrame的索引(index

在Pandas中,修改DataFrame的索引是一个常见操作,可以帮助更好地定位和引用数据行。下面是如何修改DataFrame索引的步骤和示例:

  1. 设置默认显示行数:首先,我们可以通过pd.set_option来设置Pandas默认显示的行数。这里未展示设置方法,但可以通过print(df.head())来显示前几行数据,其中df是DataFrame变量名。

  2. 直接修改索引:可以通过直接赋值给df.index属性来修改整个DataFrame的索引。例如,如果有一个DataFrame row,并且想要将索引修改为['x', 'y', 'z'],需要确保索引的长度与DataFrame的行数相匹配。如果不匹配,会导致错误。

1
row.index = ['x', 'y', 'z']

读取文件时只处理部分行

当处理大型文件时,为了测试或其他目的,可能只想读取文件的一部分。使用pd.read_csv时,可以通过nrows参数来限制读取的行数。

1
df = pd.read_csv('./LCIS.csv', nrows=3)

修改DataFrame的列名(columns

修改列名可以通过直接赋值给df.columns属性或使用rename方法。

  1. 直接修改所有列名:通过直接赋值给df.columns属性,可以为所有列设置新的列名。
1
row.columns = ['A', 'B', 'C']
  1. 使用rename方法修改列名:如果只想修改某些列的名称,可以使用rename方法,并通过columns参数传入一个字典,字典的键是旧列名,值是新列名。使用inplace=True可以直接在原DataFrame上进行修改,而不是返回一个新的DataFrame。
1
row.rename(columns={'ListingId': 'ID'}, inplace=True)

单独修改一个索引或列名

同样,使用rename方法也可以修改单个索引或列名,方法与修改列名类似。

1
row.rename(index={0: 'A'}, inplace=True)

综合示例

现在,让我们通过一个综合示例来展示如何实际应用上述操作,并提供预期的输出结果。

数据导入
1
2
3
import pandas as pd
df = pd.read_csv('LCIS.csv',nrows=5, usecols=range(10))
row = pd.DataFrame(df)
修改索引前的输出
1
2
print("修改索引前:")
print(row.head())
1
2
3
4
5
6
7
修改索引前:
ListingId 借款金额 借款期限 借款利率 借款成功日期 初始评级 借款类型 是否首标 年龄 性别
0 1693100 3629 6 12 2015/1/28 AA 普通 否 31 男
1 1713229 3000 12 12 2015/1/30 AA 普通 是 24 男
2 1904026 3629 12 12 2015/3/7 AA 普通 否 27 男
3 2158281 3919 12 18 2015/4/14 C 普通 否 28 男
4 2257194 14000 12 18 2015/4/23 C 普通 否 46 男
修改索引后的输出
1
2
3
4
# 修改索引
row.index = ['x', 'y', 'z', 'a', 'b']
print("\n修改索引后:")
print(row.head())
1
2
3
4
5
6
7
修改索引后:
ListingId 借款金额 借款期限 借款利率 借款成功日期 初始评级 借款类型 是否首标 年龄 性别
x 1693100 3629 6 12 2015/1/28 AA 普通 否 31 男
y 1713229 3000 12 12 2015/1/30 AA 普通 是 24 男
z 1904026 3629 12 12 2015/3/7 AA 普通 否 27 男
a 2158281 3919 12 18 2015/4/14 C 普通 否 28 男
b 2257194 14000 12 18 2015/4/23 C 普通 否 46 男
修改列名
1
2
3
4
# 修改列名
row.columns = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
print("\n修改列名后:")
print(row.head())
1
2
3
4
5
6
7
修改列名后:
A B C D E F G H I J
x 1693100 3629 6 12 2015/1/28 AA 普通 否 31 男
y 1713229 3000 12 12 2015/1/30 AA 普通 是 24 男
z 1904026 3629 12 12 2015/3/7 AA 普通 否 27 男
a 2158281 3919 12 18 2015/4/14 C 普通 否 28 男
b 2257194 14000 12 18 2015/4/23 C 普通 否 46 男
使用rename方法重命名列
1
2
3
4
# 使用rename方法重命名列
row.rename(columns={'A': 'ID'}, inplace=True)
print("\n使用rename方法修改列名后:")
print(row)
1
2
3
4
5
6
7
使用rename方法修改列名后:
ID B C D E F G H I J
x 1693100 3629 6 12 2015/1/28 AA 普通 否 31 男
y 1713229 3000 12 12 2015/1/30 AA 普通 是 24 男
z 1904026 3629 12 12 2015/3/7 AA 普通 否 27 男
a 2158281 3919 12 18 2015/4/14 C 普通 否 28 男
b 2257194 14000 12 18 2015/4/23 C 普通 否 46 男
单独修改一个索引
1
2
3
4
# 单独修改一个索引
row.rename(index={'x': 'A'}, inplace=True)
print("\n单独修改一个索引后:")
print(row)
1
2
3
4
5
6
7
单独修改一个索引后:
ID B C D E F G H I J
A 1693100 3629 6 12 2015/1/28 AA 普通 否 31 男
y 1713229 3000 12 12 2015/1/30 AA 普通 是 24 男
z 1904026 3629 12 12 2015/3/7 AA 普通 否 27 男
a 2158281 3919 12 18 2015/4/14 C 普通 否 28 男
b 2257194 14000 12 18 2015/4/23 C 普通 否 46 男

数据合并

concat()函数概览

pd.concat()可以沿着一条轴将多个对象堆叠到一起。主要参数包括:

  • objs:一个序列或映射,表示要合并的pandas对象。
  • axis:默认为0,表示沿着行合并;设置为1表示沿着列合并。
  • ignore_index:如果为True,不使用索引标签进行连接;这将对结果DataFrame使用默认整数索引。

在Pandas中,pd.concat()函数是合并数据的一个非常有用的工具,它允许沿着特定的轴将多个DataFrame合并在一起。下面,我们将通过具体的示例来展示如何使用pd.concat()进行数据合并,包括沿着列(axis=1)和沿着行(axis=0)的合并。每个案例都将提供代码示例和预期的输出结果。

示例数据
选择性读取行

有时候,在读取文件创建DataFrame时,可能想要跳过某些行或只读取特定的行。可以通过skiprowsnrows参数来实现这一点:

1
2
3
df = pd.read_csv('./LCIS.csv', skiprows=range(1, 4), nrows=3, usecols=range(2, 6))
res = pd.DataFrame(df)
print(res)

这里,skiprows=range(1, 4)跳过了文件的第1到第3行(注意行数是从0开始计数的),而nrows=3指定了之后只读取3行。

1
2
3
4
借款期限  借款利率     借款成功日期 初始评级
0 12 18 2015/4/14 C
1 12 18 2015/4/23 C
2 6 15 2015/4/29 B

首先,让我们定义两个DataFrame,rowres,以便进行合并操作。假设这些DataFrame已经根据上文中的说明进行了加载和修改:

1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd

# 假设这是从文件中读取的DataFrame
row = pd.read_csv('LCIS.csv', skiprows=range(1, 11), header=0, nrows=10, usecols=range(10))

# 假设res是另一个文件中读取DataFrame
res = pd.read_csv('LCIS.csv',skiprows=range(12, 20), header=0, nrows=10, usecols=range(10))
print('row DataFrame')
print(row)
print("=============================================")
print('res DataFrame')
print(res)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
row DataFrame
ListingId 借款金额 借款期限 借款利率 借款成功日期 初始评级 借款类型 是否首标 年龄 性别
0 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34 男
1 2707322 5000 3 10.0 2015/6/5 AA 普通 否 35 男
2 2722356 3132 12 20.0 2015/6/13 D 普通 否 30 男
3 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24 男
4 2850335 17640 18 16.0 2015/6/18 B 其他 是 28 男
5 3155520 7008 10 11.0 2015/7/12 AA 普通 否 34 男
6 3207478 19928 12 16.0 2015/7/14 B 其他 是 22 男
7 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43 男
8 3637812 4000 6 10.5 2015/8/17 AA 其他 是 24 男
9 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26 男
=============================================
res DataFrame
ListingId 借款金额 借款期限 借款利率 借款成功日期 初始评级 借款类型 是否首标 年龄 性别
0 1693100 3629 6 12 2015/1/28 AA 普通 否 31 男
1 1713229 3000 12 12 2015/1/30 AA 普通 是 24 男
2 1904026 3629 12 12 2015/3/7 AA 普通 否 27 男
3 2158281 3919 12 18 2015/4/14 C 普通 否 28 男
4 2257194 14000 12 18 2015/4/23 C 普通 否 46 男
5 2272036 40000 6 15 2015/4/29 B 电商 是 32 男
6 2315058 3200 3 10 2015/4/29 AA 普通 否 25 男
7 2332817 3000 6 12 2015/5/6 AA 普通 是 38 男
8 2365175 4260 7 12 2015/5/6 AA 普通 否 25 男
9 2370723 11987 12 16 2015/5/7 B 其他 否 33 女
沿着列合并DataFrame

当想要将两个DataFrame按列拼接(即并排放置),可以设置axis=1。这通常用于合并具有相同索引的DataFrame,但列不同的情况。

1
2
num = pd.concat([row, res], axis=1)
print(num)

预期输出是rowresDataFrame并排放置的结果,这里由于rowres的行数相同,因此可以直接并排合并。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   ListingId   借款金额  借款期限  借款利率     借款成功日期 初始评级 借款类型 是否首标  年龄 性别  ListingId  \
0 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34 男 1693100
1 2707322 5000 3 10.0 2015/6/5 AA 普通 否 35 男 1713229
2 2722356 3132 12 20.0 2015/6/13 D 普通 否 30 男 1904026
3 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24 男 2158281
4 2850335 17640 18 16.0 2015/6/18 B 其他 是 28 男 2257194
5 3155520 7008 10 11.0 2015/7/12 AA 普通 否 34 男 2272036
6 3207478 19928 12 16.0 2015/7/14 B 其他 是 22 男 2315058
7 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43 男 2332817
8 3637812 4000 6 10.5 2015/8/17 AA 其他 是 24 男 2365175
9 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26 男 2370723

借款金额 借款期限 借款利率 借款成功日期 初始评级 借款类型 是否首标 年龄 性别
0 3629 6 12 2015/1/28 AA 普通 否 31 男
1 3000 12 12 2015/1/30 AA 普通 是 24 男
2 3629 12 12 2015/3/7 AA 普通 否 27 男
3 3919 12 18 2015/4/14 C 普通 否 28 男
4 14000 12 18 2015/4/23 C 普通 否 46 男
5 40000 6 15 2015/4/29 B 电商 是 32 男
6 3200 3 10 2015/4/29 AA 普通 否 25 男
7 3000 6 12 2015/5/6 AA 普通 是 38 男
8 4260 7 12 2015/5/6 AA 普通 否 25 男
9 11987 12 16 2015/5/7 B 其他 否 33 女
沿着行合并DataFrame

如果想将两个DataFrame上下拼接,可以设置axis=0。这通常用于合并具有相同列的DataFrame,或者即使列不完全相同也可以合并,Pandas会自动处理不匹配的列。

1
2
num = pd.concat([row, res], axis=0)
print(num)

在这个例子中,由于res仅包含row的部分列,合并结果会展示所有列,不在res中的列对应的行会显示为NaN。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
   ListingId   借款金额  借款期限  借款利率     借款成功日期 初始评级 借款类型 是否首标  年龄 性别
0 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34 男
1 2707322 5000 3 10.0 2015/6/5 AA 普通 否 35 男
2 2722356 3132 12 20.0 2015/6/13 D 普通 否 30 男
3 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24 男
4 2850335 17640 18 16.0 2015/6/18 B 其他 是 28 男
5 3155520 7008 10 11.0 2015/7/12 AA 普通 否 34 男
6 3207478 19928 12 16.0 2015/7/14 B 其他 是 22 男
7 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43 男
8 3637812 4000 6 10.5 2015/8/17 AA 其他 是 24 男
9 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26 男
0 1693100 3629 6 12.0 2015/1/28 AA 普通 否 31 男
1 1713229 3000 12 12.0 2015/1/30 AA 普通 是 24 男
2 1904026 3629 12 12.0 2015/3/7 AA 普通 否 27 男
3 2158281 3919 12 18.0 2015/4/14 C 普通 否 28 男
4 2257194 14000 12 18.0 2015/4/23 C 普通 否 46 男
5 2272036 40000 6 15.0 2015/4/29 B 电商 是 32 男
6 2315058 3200 3 10.0 2015/4/29 AA 普通 否 25 男
7 2332817 3000 6 12.0 2015/5/6 AA 普通 是 38 男
8 2365175 4260 7 12.0 2015/5/6 AA 普通 否 25 男
9 2370723 11987 12 16.0 2015/5/7 B 其他 否 33 女
重置索引以避免索引重复

在进行行合并时,如果不希望保留原始的索引,可以设置ignore_index=True,以避免索引重复的问题。

1
2
num = pd.concat([row, res], axis=0, ignore_index=True)
print(num)

这会创建一个新的DataFrame,其中索引是重新生成的,从0开始,避免了任何索引重复的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    ListingId   借款金额  借款期限  借款利率     借款成功日期 初始评级 借款类型 是否首标  年龄 性别
0 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34 男
1 2707322 5000 3 10.0 2015/6/5 AA 普通 否 35 男
2 2722356 3132 12 20.0 2015/6/13 D 普通 否 30 男
3 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24 男
4 2850335 17640 18 16.0 2015/6/18 B 其他 是 28 男
5 3155520 7008 10 11.0 2015/7/12 AA 普通 否 34 男
6 3207478 19928 12 16.0 2015/7/14 B 其他 是 22 男
7 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43 男
8 3637812 4000 6 10.5 2015/8/17 AA 其他 是 24 男
9 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26 男
10 1693100 3629 6 12.0 2015/1/28 AA 普通 否 31 男
11 1713229 3000 12 12.0 2015/1/30 AA 普通 是 24 男
12 1904026 3629 12 12.0 2015/3/7 AA 普通 否 27 男
13 2158281 3919 12 18.0 2015/4/14 C 普通 否 28 男
14 2257194 14000 12 18.0 2015/4/23 C 普通 否 46 男
15 2272036 40000 6 15.0 2015/4/29 B 电商 是 32 男
16 2315058 3200 3 10.0 2015/4/29 AA 普通 否 25 男
17 2332817 3000 6 12.0 2015/5/6 AA 普通 是 38 男
18 2365175 4260 7 12.0 2015/5/6 AA 普通 否 25 男
19 2370723 11987 12 16.0 2015/5/7 B 其他 否 33 女

merge()

在Pandas中,pd.merge()函数提供了一个强大的方式来合并两个DataFrame,基于一个或多个共同的键。下面,将详细介绍如何使用pd.merge()进行数据合并,包括基于相同列的简单合并、处理行的选择性读取、以及基于不同列名进行合并。每个案例都会提供代码示例和预期的输出。

示例数据

使用concat()示例中同样的数据

基于共同列合并DataFrame

当两个DataFrame具有至少一个共同的列时,可以使用这个共同列作为合并的基础。以下是如何根据共同列'借款期限'合并两个DataFrame的示例:

1
2
3
4
5
import pandas as pd

# 假设row和res是concat()示例中已经加载的DataFrame,且它们有一个共同列'借款期限'
num = pd.merge(row, res, on='借款期限')
print(num)

在这个示例中,pd.merge()通过on='借款期限'参数指定了合并的基础列。这将只保留那些在两个DataFrame中都存在的'借款期限'值的行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
    ListingId_x  借款金额_x  借款期限  借款利率_x   借款成功日期_x 初始评级_x 借款类型_x 是否首标_x  年龄_x  \
0 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
1 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
2 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
3 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
4 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
5 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
6 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
7 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
8 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
9 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
10 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
11 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
12 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
13 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
14 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
15 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
16 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
17 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
18 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
19 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
20 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
21 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
22 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
23 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
24 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
25 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
26 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
27 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
28 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
29 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
30 2707322 5000 3 10.0 2015/6/5 AA 普通 否 35
31 3637812 4000 6 10.5 2015/8/17 AA 其他 是 24
32 3637812 4000 6 10.5 2015/8/17 AA 其他 是 24
33 3637812 4000 6 10.5 2015/8/17 AA 其他 是 24

性别_x ListingId_y 借款金额_y 借款利率_y 借款成功日期_y 初始评级_y 借款类型_y 是否首标_y 年龄_y \
0 男 1713229 3000 12 2015/1/30 AA 普通 是 24
1 男 1904026 3629 12 2015/3/7 AA 普通 否 27
2 男 2158281 3919 18 2015/4/14 C 普通 否 28
3 男 2257194 14000 18 2015/4/23 C 普通 否 46
4 男 2370723 11987 16 2015/5/7 B 其他 否 33
5 男 1713229 3000 12 2015/1/30 AA 普通 是 24
6 男 1904026 3629 12 2015/3/7 AA 普通 否 27
7 男 2158281 3919 18 2015/4/14 C 普通 否 28
8 男 2257194 14000 18 2015/4/23 C 普通 否 46
9 男 2370723 11987 16 2015/5/7 B 其他 否 33
10 男 1713229 3000 12 2015/1/30 AA 普通 是 24
11 男 1904026 3629 12 2015/3/7 AA 普通 否 27
12 男 2158281 3919 18 2015/4/14 C 普通 否 28
13 男 2257194 14000 18 2015/4/23 C 普通 否 46
14 男 2370723 11987 16 2015/5/7 B 其他 否 33
15 男 1713229 3000 12 2015/1/30 AA 普通 是 24
16 男 1904026 3629 12 2015/3/7 AA 普通 否 27
17 男 2158281 3919 18 2015/4/14 C 普通 否 28
18 男 2257194 14000 18 2015/4/23 C 普通 否 46
19 男 2370723 11987 16 2015/5/7 B 其他 否 33
20 男 1713229 3000 12 2015/1/30 AA 普通 是 24
21 男 1904026 3629 12 2015/3/7 AA 普通 否 27
22 男 2158281 3919 18 2015/4/14 C 普通 否 28
23 男 2257194 14000 18 2015/4/23 C 普通 否 46
24 男 2370723 11987 16 2015/5/7 B 其他 否 33
25 男 1713229 3000 12 2015/1/30 AA 普通 是 24
26 男 1904026 3629 12 2015/3/7 AA 普通 否 27
27 男 2158281 3919 18 2015/4/14 C 普通 否 28
28 男 2257194 14000 18 2015/4/23 C 普通 否 46
29 男 2370723 11987 16 2015/5/7 B 其他 否 33
30 男 2315058 3200 10 2015/4/29 AA 普通 否 25
31 男 1693100 3629 12 2015/1/28 AA 普通 否 31
32 男 2272036 40000 15 2015/4/29 B 电商 是 32
33 男 2332817 3000 12 2015/5/6 AA 普通 是 38

性别_y
0 男
1 男
2 男
3 男
4 女
5 男
6 男
7 男
8 男
9 女
10 男
11 男
12 男
13 男
14 女
15 男
16 男
17 男
18 男
19 女
20 男
21 男
22 男
23 男
24 女
25 男
26 男
27 男
28 男
29 女
30 男
31 男
32 男
33 男
基于不同列名的合并

如果两个DataFrame要合并的列名不同,可以分别使用left_onright_on参数来指定各自的列名:

1
2
num = pd.merge(row, res, left_on='借款期限', right_on='借款利率')
print(num)

在这个例子中,尽管rowres中要合并的列名不同,但通过left_onright_on参数,我们能够指定如何将两个DataFrame基于对应列的值进行合并。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
    ListingId_x  借款金额_x  借款期限_x  借款利率_x   借款成功日期_x 初始评级_x 借款类型_x 是否首标_x  年龄_x  \
0 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
1 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
2 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
3 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
4 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
5 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
6 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
7 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
8 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
9 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
10 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
11 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
12 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
13 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
14 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
15 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
16 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
17 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
18 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
19 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
20 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
21 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
22 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
23 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
24 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
25 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
26 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
27 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
28 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
29 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
30 2850335 17640 18 16.0 2015/6/18 B 其他 是 28
31 2850335 17640 18 16.0 2015/6/18 B 其他 是 28
32 3155520 7008 10 11.0 2015/7/12 AA 普通 否 34

性别_x ListingId_y 借款金额_y 借款期限_y 借款利率_y 借款成功日期_y 初始评级_y 借款类型_y 是否首标_y \
0 男 1693100 3629 6 12 2015/1/28 AA 普通 否
1 男 1713229 3000 12 12 2015/1/30 AA 普通 是
2 男 1904026 3629 12 12 2015/3/7 AA 普通 否
3 男 2332817 3000 6 12 2015/5/6 AA 普通 是
4 男 2365175 4260 7 12 2015/5/6 AA 普通 否
5 男 1693100 3629 6 12 2015/1/28 AA 普通 否
6 男 1713229 3000 12 12 2015/1/30 AA 普通 是
7 男 1904026 3629 12 12 2015/3/7 AA 普通 否
8 男 2332817 3000 6 12 2015/5/6 AA 普通 是
9 男 2365175 4260 7 12 2015/5/6 AA 普通 否
10 男 1693100 3629 6 12 2015/1/28 AA 普通 否
11 男 1713229 3000 12 12 2015/1/30 AA 普通 是
12 男 1904026 3629 12 12 2015/3/7 AA 普通 否
13 男 2332817 3000 6 12 2015/5/6 AA 普通 是
14 男 2365175 4260 7 12 2015/5/6 AA 普通 否
15 男 1693100 3629 6 12 2015/1/28 AA 普通 否
16 男 1713229 3000 12 12 2015/1/30 AA 普通 是
17 男 1904026 3629 12 12 2015/3/7 AA 普通 否
18 男 2332817 3000 6 12 2015/5/6 AA 普通 是
19 男 2365175 4260 7 12 2015/5/6 AA 普通 否
20 男 1693100 3629 6 12 2015/1/28 AA 普通 否
21 男 1713229 3000 12 12 2015/1/30 AA 普通 是
22 男 1904026 3629 12 12 2015/3/7 AA 普通 否
23 男 2332817 3000 6 12 2015/5/6 AA 普通 是
24 男 2365175 4260 7 12 2015/5/6 AA 普通 否
25 男 1693100 3629 6 12 2015/1/28 AA 普通 否
26 男 1713229 3000 12 12 2015/1/30 AA 普通 是
27 男 1904026 3629 12 12 2015/3/7 AA 普通 否
28 男 2332817 3000 6 12 2015/5/6 AA 普通 是
29 男 2365175 4260 7 12 2015/5/6 AA 普通 否
30 男 2158281 3919 12 18 2015/4/14 C 普通 否
31 男 2257194 14000 12 18 2015/4/23 C 普通 否
32 男 2315058 3200 3 10 2015/4/29 AA 普通 否

年龄_y 性别_y
0 31 男
1 24 男
2 27 男
3 38 男
4 25 男
5 31 男
6 24 男
7 27 男
8 38 男
9 25 男
10 31 男
11 24 男
12 27 男
13 38 男
14 25 男
15 31 男
16 24 男
17 27 男
18 38 男
19 25 男
20 31 男
21 24 男
22 27 男
23 38 男
24 25 男
25 31 男
26 24 男
27 27 男
28 38 男
29 25 男
30 28 男
31 46 男
32 25 男
指定合并方式

pd.merge()允许通过how参数来指定合并方式,包括'inner'(内连接)、'outer'(外连接)、'left'(左连接)和'right'(右连接):

1
2
num = pd.merge(row, res, left_on='借款期限', right_on='借款利率', how='inner')
print(num)

这里,how='inner'意味着结果中只包含那些两个DataFrame在指定列上都有匹配值的行。不同的how值可以根据需要选择,以实现不同的合并逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
    ListingId_x  借款金额_x  借款期限_x  借款利率_x   借款成功日期_x 初始评级_x 借款类型_x 是否首标_x  年龄_x  \
0 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
1 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
2 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
3 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
4 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34
5 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
6 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
7 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
8 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
9 2722356 3132 12 20.0 2015/6/13 D 普通 否 30
10 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
11 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
12 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
13 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
14 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24
15 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
16 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
17 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
18 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
19 3207478 19928 12 16.0 2015/7/14 B 其他 是 22
20 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
21 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
22 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
23 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
24 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43
25 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
26 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
27 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
28 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
29 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26
30 2850335 17640 18 16.0 2015/6/18 B 其他 是 28
31 2850335 17640 18 16.0 2015/6/18 B 其他 是 28
32 3155520 7008 10 11.0 2015/7/12 AA 普通 否 34

性别_x ListingId_y 借款金额_y 借款期限_y 借款利率_y 借款成功日期_y 初始评级_y 借款类型_y 是否首标_y \
0 男 1693100 3629 6 12 2015/1/28 AA 普通 否
1 男 1713229 3000 12 12 2015/1/30 AA 普通 是
2 男 1904026 3629 12 12 2015/3/7 AA 普通 否
3 男 2332817 3000 6 12 2015/5/6 AA 普通 是
4 男 2365175 4260 7 12 2015/5/6 AA 普通 否
5 男 1693100 3629 6 12 2015/1/28 AA 普通 否
6 男 1713229 3000 12 12 2015/1/30 AA 普通 是
7 男 1904026 3629 12 12 2015/3/7 AA 普通 否
8 男 2332817 3000 6 12 2015/5/6 AA 普通 是
9 男 2365175 4260 7 12 2015/5/6 AA 普通 否
10 男 1693100 3629 6 12 2015/1/28 AA 普通 否
11 男 1713229 3000 12 12 2015/1/30 AA 普通 是
12 男 1904026 3629 12 12 2015/3/7 AA 普通 否
13 男 2332817 3000 6 12 2015/5/6 AA 普通 是
14 男 2365175 4260 7 12 2015/5/6 AA 普通 否
15 男 1693100 3629 6 12 2015/1/28 AA 普通 否
16 男 1713229 3000 12 12 2015/1/30 AA 普通 是
17 男 1904026 3629 12 12 2015/3/7 AA 普通 否
18 男 2332817 3000 6 12 2015/5/6 AA 普通 是
19 男 2365175 4260 7 12 2015/5/6 AA 普通 否
20 男 1693100 3629 6 12 2015/1/28 AA 普通 否
21 男 1713229 3000 12 12 2015/1/30 AA 普通 是
22 男 1904026 3629 12 12 2015/3/7 AA 普通 否
23 男 2332817 3000 6 12 2015/5/6 AA 普通 是
24 男 2365175 4260 7 12 2015/5/6 AA 普通 否
25 男 1693100 3629 6 12 2015/1/28 AA 普通 否
26 男 1713229 3000 12 12 2015/1/30 AA 普通 是
27 男 1904026 3629 12 12 2015/3/7 AA 普通 否
28 男 2332817 3000 6 12 2015/5/6 AA 普通 是
29 男 2365175 4260 7 12 2015/5/6 AA 普通 否
30 男 2158281 3919 12 18 2015/4/14 C 普通 否
31 男 2257194 14000 12 18 2015/4/23 C 普通 否
32 男 2315058 3200 3 10 2015/4/29 AA 普通 否

年龄_y 性别_y
0 31 男
1 24 男
2 27 男
3 38 男
4 25 男
5 31 男
6 24 男
7 27 男
8 38 男
9 25 男
10 31 男
11 24 男
12 27 男
13 38 男
14 25 男
15 31 男
16 24 男
17 27 男
18 38 男
19 25 男
20 31 男
21 24 男
22 27 男
23 38 男
24 25 男
25 31 男
26 24 男
27 27 男
28 38 男
29 25 男
30 28 男
31 46 男
32 25 男

通过上述示例,可以看到pd.merge()在Pandas中合并数据时的灵活性和强大功能。这些基础知识使得在进行数据分析和处理时,能够根据实际需求选择合适的合并策略。

join()

在Pandas中,join()函数是用于将两个或多个DataFrame按照索引合并。这个函数默认执行的是左连接操作,即以调用join()的DataFrame的索引为基准。不过,可以通过how参数来指定连接类型,包括left(左连接)、right(右连接)、inner(内连接)和outer(外连接)。

警告

在尝试使用join()合并两个DataFrame时,两个DataFrame中存在相同名称的列。join()方法默认通过索引来合并数据,如果合并的DataFrame中有重叠的列名(即非索引列),则需要指定后缀来区分这些重叠的列,否则会抛出ValueError

为了解决这个问题,可以使用lsuffixrsuffix参数来为左右DataFrame中重叠的列名分别添加后缀。这样,即使列名相同,添加了后缀之后也能区分开来。

下面的代码展示了如何使用这些参数来避免错误:

1
2
3
4
5
6
# 使用lsuffix和rsuffix添加后缀
result_right = row.join(res, how='right', lsuffix='_left', rsuffix='_right')
print(result_right)

result_outer = row.join(res, how='outer', lsuffix='_left', rsuffix='_right')
print(result_outer)

在这个例子中,lsuffix='_left'会给左侧DataFrame的重叠列名添加后缀_leftrsuffix='_right'会给右侧DataFrame的重叠列名添加后缀_right。这样,即便原始列名相同,通过添加的后缀也能将它们区分开来,从而避免了错误。

如果目标是基于某些列值而不是索引来合并DataFrame,可能merge()方法更适合需求,因为它提供了更灵活的列合并选项。

左连接(Left Join)

左连接会保留左侧DataFrame的所有行,即使在右侧DataFrame中没有匹配的索引。如果右侧DataFrame中存在匹配的索引,则相应的列会被添加到结果中。如果不存在,则结果中这些列的值会设置为NaN。

1
2
3
# 左连接
result_left = row.join(res, how='left', lsuffix='_left', rsuffix='_right')
print(result_left)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
   ListingId_left  借款金额_left  借款期限_left  借款利率_left 借款成功日期_left 初始评级_left  \
0 2526671 5115 12 12.0 2015/5/23 AA
1 2707322 5000 3 10.0 2015/6/5 AA
2 2722356 3132 12 20.0 2015/6/13 D
3 2828736 3000 12 12.0 2015/6/19 AA
4 2850335 17640 18 16.0 2015/6/18 B
5 3155520 7008 10 11.0 2015/7/12 AA
6 3207478 19928 12 16.0 2015/7/14 B
7 3617672 7000 12 11.5 2015/8/12 AA
8 3637812 4000 6 10.5 2015/8/17 AA
9 3705094 1000 12 11.5 2015/8/21 AA

借款类型_left 是否首标_left 年龄_left 性别_left ListingId_right 借款金额_right \
0 普通 否 34 男 1693100 3629
1 普通 否 35 男 1713229 3000
2 普通 否 30 男 1904026 3629
3 普通 是 24 男 2158281 3919
4 其他 是 28 男 2257194 14000
5 普通 否 34 男 2272036 40000
6 其他 是 22 男 2315058 3200
7 普通 是 43 男 2332817 3000
8 其他 是 24 男 2365175 4260
9 普通 是 26 男 2370723 11987

借款期限_right 借款利率_right 借款成功日期_right 初始评级_right 借款类型_right 是否首标_right \
0 6 12 2015/1/28 AA 普通 否
1 12 12 2015/1/30 AA 普通 是
2 12 12 2015/3/7 AA 普通 否
3 12 18 2015/4/14 C 普通 否
4 12 18 2015/4/23 C 普通 否
5 6 15 2015/4/29 B 电商 是
6 3 10 2015/4/29 AA 普通 否
7 6 12 2015/5/6 AA 普通 是
8 7 12 2015/5/6 AA 普通 否
9 12 16 2015/5/7 B 其他 否

年龄_right 性别_right
0 31 男
1 24 男
2 27 男
3 28 男
4 46 男
5 32 男
6 25 男
7 38 男
8 25 男
9 33 女
右连接(Right Join)

右连接与左连接相反,它会保留右侧DataFrame的所有行,即使在左侧DataFrame中没有匹配的索引。

1
2
3
# 右连接
result_right = row.join(res, how='right', lsuffix='_left', rsuffix='_right')
print(result_right)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
   ListingId_left  借款金额_left  借款期限_left  借款利率_left 借款成功日期_left 初始评级_left  \
0 2526671 5115 12 12.0 2015/5/23 AA
1 2707322 5000 3 10.0 2015/6/5 AA
2 2722356 3132 12 20.0 2015/6/13 D
3 2828736 3000 12 12.0 2015/6/19 AA
4 2850335 17640 18 16.0 2015/6/18 B
5 3155520 7008 10 11.0 2015/7/12 AA
6 3207478 19928 12 16.0 2015/7/14 B
7 3617672 7000 12 11.5 2015/8/12 AA
8 3637812 4000 6 10.5 2015/8/17 AA
9 3705094 1000 12 11.5 2015/8/21 AA

借款类型_left 是否首标_left 年龄_left 性别_left ListingId_right 借款金额_right \
0 普通 否 34 男 1693100 3629
1 普通 否 35 男 1713229 3000
2 普通 否 30 男 1904026 3629
3 普通 是 24 男 2158281 3919
4 其他 是 28 男 2257194 14000
5 普通 否 34 男 2272036 40000
6 其他 是 22 男 2315058 3200
7 普通 是 43 男 2332817 3000
8 其他 是 24 男 2365175 4260
9 普通 是 26 男 2370723 11987

借款期限_right 借款利率_right 借款成功日期_right 初始评级_right 借款类型_right 是否首标_right \
0 6 12 2015/1/28 AA 普通 否
1 12 12 2015/1/30 AA 普通 是
2 12 12 2015/3/7 AA 普通 否
3 12 18 2015/4/14 C 普通 否
4 12 18 2015/4/23 C 普通 否
5 6 15 2015/4/29 B 电商 是
6 3 10 2015/4/29 AA 普通 否
7 6 12 2015/5/6 AA 普通 是
8 7 12 2015/5/6 AA 普通 否
9 12 16 2015/5/7 B 其他 否

年龄_right 性别_right
0 31 男
1 24 男
2 27 男
3 28 男
4 46 男
5 32 男
6 25 男
7 38 男
8 25 男
9 33 女
外连接(Outer Join)

外连接会保留左右两侧DataFrame中的所有行。如果某些行在另一侧没有匹配的索引,则结果DataFrame中这些行的相应列会被设置为NaN。

1
2
3
# 外连接
result_outer = row.join(res, how='outer', lsuffix='_left', rsuffix='_right')
print(result_outer)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
   ListingId_left  借款金额_left  借款期限_left  借款利率_left 借款成功日期_left 初始评级_left  \
0 2526671 5115 12 12.0 2015/5/23 AA
1 2707322 5000 3 10.0 2015/6/5 AA
2 2722356 3132 12 20.0 2015/6/13 D
3 2828736 3000 12 12.0 2015/6/19 AA
4 2850335 17640 18 16.0 2015/6/18 B
5 3155520 7008 10 11.0 2015/7/12 AA
6 3207478 19928 12 16.0 2015/7/14 B
7 3617672 7000 12 11.5 2015/8/12 AA
8 3637812 4000 6 10.5 2015/8/17 AA
9 3705094 1000 12 11.5 2015/8/21 AA

借款类型_left 是否首标_left 年龄_left 性别_left ListingId_right 借款金额_right \
0 普通 否 34 男 1693100 3629
1 普通 否 35 男 1713229 3000
2 普通 否 30 男 1904026 3629
3 普通 是 24 男 2158281 3919
4 其他 是 28 男 2257194 14000
5 普通 否 34 男 2272036 40000
6 其他 是 22 男 2315058 3200
7 普通 是 43 男 2332817 3000
8 其他 是 24 男 2365175 4260
9 普通 是 26 男 2370723 11987

借款期限_right 借款利率_right 借款成功日期_right 初始评级_right 借款类型_right 是否首标_right \
0 6 12 2015/1/28 AA 普通 否
1 12 12 2015/1/30 AA 普通 是
2 12 12 2015/3/7 AA 普通 否
3 12 18 2015/4/14 C 普通 否
4 12 18 2015/4/23 C 普通 否
5 6 15 2015/4/29 B 电商 是
6 3 10 2015/4/29 AA 普通 否
7 6 12 2015/5/6 AA 普通 是
8 7 12 2015/5/6 AA 普通 否
9 12 16 2015/5/7 B 其他 否

年龄_right 性别_right
0 31 男
1 24 男
2 27 男
3 28 男
4 46 男
5 32 男
6 25 男
7 38 男
8 25 男
9 33 女
内连接(Inner Join)

内连接只保留两个DataFrame中都有匹配的行。如果某行在另一侧没有匹配的索引,则这行不会出现在结果DataFrame中。

1
2
# 内连接通常使用merge()而不是join(), 因为join()默认基于索引连接
# result_inner = row.join(res, how='inner') # 不适用
使用示例

在的例子中,使用join()可能不会直接给出期望的结果,因为join()默认是按索引进行合并的。如果DataFrame没有设置索引或者两个DataFrame的索引并不完全匹配,那么合并的结果可能不会是期望的。在这种情况下,使用merge()函数可能更为合适,因为它允许指定合并的列。

不过,如果仍想使用join()并基于列进行合并,可能需要先将某个列设置为索引,然后再进行连接操作。这里给出的代码示例直接使用join(),假设已经有了适当的索引设置。

1
2
3
4
5
6
# 假设df和res是要合并的DataFrame
df = pd.read_csv('./LCIS.csv', nrows=5, usecols=range(3,6))
res = pd.DataFrame(df)
# 尝试使用右连接和外连接,展示效果
print(row.join(res, how='right', lsuffix='_left', rsuffix='_right'))
print(row.join(res, how='outer', lsuffix='_left', rsuffix='_right'))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
   ListingId   借款金额  借款期限  借款利率_left 借款成功日期_left 初始评级_left 借款类型 是否首标  年龄 性别  \
0 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34 男
1 2707322 5000 3 10.0 2015/6/5 AA 普通 否 35 男
2 2722356 3132 12 20.0 2015/6/13 D 普通 否 30 男
3 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24 男
4 2850335 17640 18 16.0 2015/6/18 B 其他 是 28 男

借款利率_right 借款成功日期_right 初始评级_right
0 12 2015/1/28 AA
1 12 2015/1/30 AA
2 12 2015/3/7 AA
3 18 2015/4/14 C
4 18 2015/4/23 C
ListingId 借款金额 借款期限 借款利率_left 借款成功日期_left 初始评级_left 借款类型 是否首标 年龄 性别 \
0 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34 男
1 2707322 5000 3 10.0 2015/6/5 AA 普通 否 35 男
2 2722356 3132 12 20.0 2015/6/13 D 普通 否 30 男
3 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24 男
4 2850335 17640 18 16.0 2015/6/18 B 其他 是 28 男
5 3155520 7008 10 11.0 2015/7/12 AA 普通 否 34 男
6 3207478 19928 12 16.0 2015/7/14 B 其他 是 22 男
7 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43 男
8 3637812 4000 6 10.5 2015/8/17 AA 其他 是 24 男
9 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26 男

借款利率_right 借款成功日期_right 初始评级_right
0 12.0 2015/1/28 AA
1 12.0 2015/1/30 AA
2 12.0 2015/3/7 AA
3 18.0 2015/4/14 C
4 18.0 2015/4/23 C
5 NaN NaN NaN
6 NaN NaN NaN
7 NaN NaN NaN
8 NaN NaN NaN
9 NaN NaN NaN

如果DataFrame没有公共列作为索引,可能需要先使用.set_index()方法来设置索引。

数据删除

当处理数据集时,删除不需要的列或行是常见的数据清理步骤。在Pandas中,可以通过del语句或DataFrame.drop方法来实现。下面是如何使用这两种方法来删除数据的详细说明和示例:

使用del语句删除列

del语句是Python的一个内置功能,它可以从DataFrame中直接删除指定的列。使用del语句时,更改是立即生效的,并且直接在原DataFrame上进行,不返回新的DataFrame。

示例代码:

1
del row['ListingId']

这行代码会从row DataFrame中删除名为'ListingId'的列。

使用drop方法删除数据

drop方法在Pandas中更加灵活,可以用于删除行或列,且可以控制是直接在原DataFrame上进行修改还是返回一个新的DataFrame。

删除行:
1
2
print(row.drop(0))  # 删除索引为0的行,不修改原DataFrame,除非指定inplace=True
print(row.drop([1, 2], inplace=False)) # 删除索引为1和2的行,不修改原DataFrame
删除列:
1
print(row.drop(['ListingId'], axis=1))  # 删除名为'ListingId'的列,不修改原DataFrame,除非指定inplace=True

在使用drop方法时,重要的参数包括:

  • labels: 指定要删除的行标签或列名称。
  • axis: 通过设置01指定删除行或列。0代表行,1代表列。
  • inplace: 通过设置TrueFalse指定是否在原地修改DataFrame。True表示在原DataFrame上修改,False(默认值)表示返回一个新的DataFrame,原DataFrame不变。

Pandas数据清洗

在数据分析过程中,经常会遇到包含重复行的数据集,这可能会对分析结果产生不利影响。Pandas提供了方便的工具来帮助识别和删除这些重复的数据。下面是如何在Pandas中清洗重复数据的详细说明和示例:

清洗重复数据

读取数据

首先,我们通过读取一个CSV文件来创建一个DataFrame,作为处理重复数据的示例:

1
2
3
4
5
import pandas as pd

# 读取50行数据
df = pd.read_csv('./LCIS.csv', nrows=50)
row = pd.DataFrame(df)

检查重复行

使用DataFrame.duplicated()方法可以检查DataFrame中的重复行。此方法返回一个布尔系列,其中True表示对应的行是重复的,而False表示行是唯一的。

1
print(row.duplicated())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
0     False
1 False
2 False
3 False
4 False
5 False
6 False
7 False
8 False
9 False
10 False
11 False
12 False
13 False
14 False
15 False
16 False
17 False
18 False
19 False
20 False
21 False
22 False
23 False
24 False
25 False
26 False
27 False
28 False
29 False
30 False
31 False
32 False
33 False
34 False
35 False
36 False
37 False
38 False
39 False
40 False
41 False
42 False
43 False
44 False
45 False
46 False
47 False
48 False
49 False
dtype: bool

此外,还可以通过对一个简单的DataFrame进行操作来理解重复值的检查:

1
2
3
4
5
6
7
data = {'A': [1, 1, 2, 3, 3],
'B': ['a', 'a', 'b', 'c', 'c']}
df = pd.DataFrame(data)

# 统计重复行的个数
df_count = df.duplicated().sum()
print(df_count)
1
2

删除重复行

使用DataFrame.drop_duplicates()方法可以删除DataFrame中的重复行。如果设置inplace=True,则会在原地修改DataFrame,而不是返回一个新的DataFrame。

1
2
3
4
5
6
7
# 删除重复行,并在原地修改DataFrame
row.drop_duplicates(inplace=True)
print(row)
print("=============================================")
# 对于之前创建的简单DataFrame,也删除重复行
df.drop_duplicates(inplace=True)
print(df)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
    ListingId   借款金额  借款期限  借款利率     借款成功日期 初始评级   借款类型 是否首标  年龄 性别  ...  \
0 1693100 3629 6 12.0 2015/1/28 AA 普通 否 31 男 ...
1 1713229 3000 12 12.0 2015/1/30 AA 普通 是 24 男 ...
2 1904026 3629 12 12.0 2015/3/7 AA 普通 否 27 男 ...
3 2158281 3919 12 18.0 2015/4/14 C 普通 否 28 男 ...
4 2257194 14000 12 18.0 2015/4/23 C 普通 否 46 男 ...
5 2272036 40000 6 15.0 2015/4/29 B 电商 是 32 男 ...
6 2315058 3200 3 10.0 2015/4/29 AA 普通 否 25 男 ...
7 2332817 3000 6 12.0 2015/5/6 AA 普通 是 38 男 ...
8 2365175 4260 7 12.0 2015/5/6 AA 普通 否 25 男 ...
9 2370723 11987 12 16.0 2015/5/7 B 其他 否 33 女 ...
10 2526671 5115 12 12.0 2015/5/23 AA 普通 否 34 男 ...
11 2707322 5000 3 10.0 2015/6/5 AA 普通 否 35 男 ...
12 2722356 3132 12 20.0 2015/6/13 D 普通 否 30 男 ...
13 2828736 3000 12 12.0 2015/6/19 AA 普通 是 24 男 ...
14 2850335 17640 18 16.0 2015/6/18 B 其他 是 28 男 ...
15 3155520 7008 10 11.0 2015/7/12 AA 普通 否 34 男 ...
16 3207478 19928 12 16.0 2015/7/14 B 其他 是 22 男 ...
17 3617672 7000 12 11.5 2015/8/12 AA 普通 是 43 男 ...
18 3637812 4000 6 10.5 2015/8/17 AA 其他 是 24 男 ...
19 3705094 1000 12 11.5 2015/8/21 AA 普通 是 26 男 ...
20 3846919 5719 6 18.0 2015/8/26 C 普通 否 34 男 ...
21 7285364 8000 12 20.0 2016/1/6 C 普通 否 26 男 ...
22 7447346 4650 12 22.0 2016/1/9 C 普通 否 29 男 ...
23 7760072 9000 12 20.0 2016/1/21 C 其他 是 37 男 ...
24 7777242 9000 12 20.0 2016/1/21 C 普通 是 29 女 ...
25 7966976 8500 12 20.0 2016/1/24 C 普通 否 43 男 ...
26 8148541 13500 12 20.0 2016/1/28 C 普通 否 32 女 ...
27 8260540 6500 12 20.0 2016/1/30 C 普通 否 26 男 ...
28 8297477 6500 12 22.0 2016/1/31 C 普通 否 35 男 ...
29 8359807 8000 12 18.0 2016/2/3 B 普通 是 27 男 ...
30 8377465 11500 12 20.0 2016/2/2 C 普通 否 46 男 ...
31 8883343 25000 12 20.0 2016/2/23 C 普通 否 27 男 ...
32 8978256 8000 12 18.0 2016/2/25 B APP闪电 是 23 男 ...
33 8987694 5000 6 20.0 2016/2/26 C 普通 否 42 男 ...
34 9045950 4000 6 18.0 2016/2/28 B APP闪电 是 21 男 ...
35 9182372 8000 12 18.0 2016/3/2 B APP闪电 是 46 男 ...
36 9482974 3300 6 20.0 2016/3/11 C 普通 否 36 女 ...
37 9581580 7000 12 18.0 2016/3/12 B APP闪电 是 23 女 ...
38 9597362 1000 6 10.0 2016/3/17 AA 普通 是 23 男 ...
39 9601032 3000 12 18.0 2016/3/13 B APP闪电 是 25 女 ...
40 9602590 1200 12 12.0 2016/3/13 AA APP闪电 是 24 男 ...
41 9809712 4000 12 16.0 2016/3/20 A APP闪电 是 21 女 ...
42 9993691 3000 12 18.0 2016/3/26 B APP闪电 是 26 男 ...
43 10240655 2725 12 18.0 2016/4/4 B 普通 否 32 男 ...
44 10259916 1500 12 20.0 2016/3/29 C APP闪电 是 22 女 ...
45 10410378 4497 6 18.0 2016/4/1 B 其他 否 31 女 ...
46 10604020 2055 6 18.0 2016/4/6 B 普通 否 25 男 ...
47 10646264 2000 12 12.0 2016/4/7 AA APP闪电 是 25 女 ...
48 10829990 5782 12 20.0 2016/4/12 C 其他 否 32 男 ...
49 11055233 4139 12 22.0 2016/4/17 C 普通 否 36 男 ...

待还利息 标当前逾期天数 标当前状态 上次还款日期 上次还款本金 上次还款利息 下次计划还款日期 下次计划还款本金 \
0 0.00 0 已还清 2015/7/28 34.20 0.30 NaN NaN
1 0.00 0 已还清 2015/10/19 173.39 1.05 NaN NaN
2 0.00 0 已还清 2016/3/6 44.04 0.38 NaN NaN
3 0.00 0 已还清 2015/5/19 92.34 0.22 NaN NaN
4 9.92 589 逾期中 NaN NaN NaN 2015/5/23 7.66
5 0.00 0 已还清 2015/10/27 35.43 0.42 NaN NaN
6 0.00 0 已还清 2015/7/17 134.45 1.11 NaN NaN
7 0.00 0 已还清 2015/11/6 8.74 0.05 NaN NaN
8 0.00 0 已还清 2015/8/5 29.59 0.00 NaN NaN
9 0.00 0 已还清 2016/1/22 35.16 0.18 NaN NaN
10 0.00 0 已还清 2016/5/22 3.58 0.00 NaN NaN
11 0.00 0 已还清 2015/9/5 63.20 0.51 NaN NaN
12 0.00 0 已还清 2015/7/20 7.31 0.00 NaN NaN
13 0.00 0 已还清 2016/4/21 52.54 0.01 NaN NaN
14 0.25 0 正常还款中 2016/12/15 1.14 0.11 2017/1/18 1.16
15 0.00 0 已还清 2016/5/12 52.11 0.44 NaN NaN
16 0.00 0 已还清 2016/12/13 26.74 0.28 NaN NaN
17 0.00 0 已还清 2015/10/18 43.94 0.36 NaN NaN
18 0.00 0 已还清 2015/9/14 300.00 2.45 NaN NaN
19 0.00 0 已还清 2016/8/20 13.22 0.07 NaN NaN
20 0.00 0 已还清 2015/11/15 33.84 0.32 NaN NaN
21 2.02 179 逾期中 2016/6/6 4.05 0.58 2016/7/6 4.12
22 0.00 0 已还清 2016/11/25 9.14 0.05 NaN NaN
23 0.02 0 正常还款中 2016/12/20 4.48 0.15 2017/1/21 4.61
24 0.02 0 正常还款中 2016/12/20 4.48 0.15 2017/1/21 4.61
25 0.02 0 正常还款中 2016/12/24 4.48 0.15 2017/1/24 4.61
26 0.00 0 已还清 2016/8/26 22.08 0.00 NaN NaN
27 0.17 2 逾期中 2016/11/30 4.40 0.23 2016/12/30 4.48
28 0.04 0 正常还款中 2016/12/31 4.51 0.16 2017/1/31 4.63
29 0.04 0 正常还款中 2016/12/3 1.40 0.06 2017/1/3 1.42
30 0.02 0 正常还款中 2016/12/18 4.48 0.15 2017/2/2 4.61
31 0.00 0 已还清 2016/12/23 4.61 0.02 NaN NaN
32 0.14 0 正常还款中 2016/12/30 4.38 0.20 2017/1/25 4.44
33 0.00 0 已还清 2016/6/29 17.24 0.00 NaN NaN
34 0.00 0 已还清 2016/8/23 8.68 0.09 NaN NaN
35 0.34 0 正常还款中 2016/12/1 4.31 0.27 2017/1/2 4.38
36 0.00 0 已还清 2016/9/3 8.71 0.11 NaN NaN
37 0.34 0 正常还款中 2016/12/10 4.31 0.27 2017/1/12 4.38
38 0.00 0 已还清 2016/9/17 85.08 0.70 NaN NaN
39 0.34 0 正常还款中 2016/12/11 4.31 0.27 2017/1/13 4.38
40 2.55 0 正常还款中 2016/12/14 42.68 1.74 2017/1/13 43.11
41 0.30 0 正常还款中 2016/12/23 4.30 0.23 2017/1/20 4.35
42 0.00 0 已还清 2016/12/23 4.58 0.00 NaN NaN
43 0.14 0 正常还款中 2016/12/28 4.38 0.20 2017/3/4 4.44
44 0.40 0 正常还款中 2016/12/29 4.33 0.30 2017/1/29 4.40
45 0.00 0 已还清 2016/8/29 8.68 0.00 NaN NaN
46 0.00 0 已还清 2016/8/28 17.19 0.16 NaN NaN
47 1.66 0 正常还款中 2016/12/8 16.90 0.86 2017/1/7 0.00
48 0.81 0 正常还款中 2016/12/10 4.94 0.43 2017/1/12 5.02
49 0.00 0 已还清 2016/10/24 26.38 0.09 NaN NaN

下次计划还款利息 recorddate
0 NaN 2016/12/31
1 NaN 2016/12/31
2 NaN 2016/12/31
3 NaN 2016/12/31
4 1.50 2016/12/31
5 NaN 2016/12/31
6 NaN 2016/12/31
7 NaN 2016/12/31
8 NaN 2016/12/31
9 NaN 2016/12/31
10 NaN 2016/12/31
11 NaN 2016/12/31
12 NaN 2016/12/31
13 NaN 2016/12/31
14 0.09 2016/12/31
15 NaN 2016/12/31
16 NaN 2016/12/31
17 NaN 2016/12/31
18 NaN 2016/12/31
19 NaN 2016/12/31
20 NaN 2016/12/31
21 0.51 2016/12/31
22 NaN 2016/12/31
23 0.02 2016/12/31
24 0.02 2016/12/31
25 0.02 2016/12/31
26 NaN 2016/12/31
27 0.15 2016/12/31
28 0.04 2016/12/31
29 0.04 2016/12/31
30 0.02 2016/12/31
31 NaN 2016/12/31
32 0.14 2016/12/31
33 NaN 2016/12/31
34 NaN 2016/12/31
35 0.20 2016/12/31
36 NaN 2016/12/31
37 0.20 2016/12/31
38 NaN 2016/12/31
39 0.20 2016/12/31
40 1.31 2016/12/31
41 0.18 2016/12/31
42 NaN 2016/12/31
43 0.14 2016/12/31
44 0.23 2016/12/31
45 NaN 2016/12/31
46 NaN 2016/12/31
47 0.00 2016/12/31
48 0.35 2016/12/31
49 NaN 2016/12/31

[50 rows x 37 columns]
=============================================
A B
0 1 a
2 2 b
3 3 c

通过这种方式,可以有效地清理数据集中的重复项,确保进行数据分析时数据的准确性和可靠性。在实际的数据处理中,根据数据的具体情况和需求,合理地使用这些方法可以大大提高数据分析的质量和效率。

清洗空值

在数据处理和分析中,处理缺失值是一个重要的步骤,因为缺失值可能会影响数据分析的结果。Pandas 提供了多种方法来处理 DataFrame 中的缺失值。下面我们将详细探讨如何统计空值,计算缺失率,删除含有空值的行或列,以及填充空值的不同方法。

统计空值和计算缺失率

统计空值数量
1
2
3
4
5
6
7
8
9
import pandas as pd

# 读取数据
df = pd.read_csv('./LCIS.csv', nrows=50)
row = pd.DataFrame(df)

# 统计各列空值的数量
res = row.isnull().sum()
print(res)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
ListingId      0
借款金额 0
借款期限 0
借款利率 0
借款成功日期 0
初始评级 0
借款类型 0
是否首标 0
年龄 0
性别 0
手机认证 0
户口认证 0
视频认证 0
学历认证 0
征信认证 0
淘宝认证 0
历史成功借款次数 0
历史成功借款金额 0
总待还本金 0
历史正常还款期数 0
历史逾期还款期数 0
我的投资金额 0
当前到期期数 0
当前还款期数 0
已还本金 0
已还利息 0
待还本金 0
待还利息 0
标当前逾期天数 0
标当前状态 0
上次还款日期 1
上次还款本金 1
上次还款利息 1
下次计划还款日期 30
下次计划还款本金 30
下次计划还款利息 30
recorddate 0
dtype: int64
计算缺失率
  • 计算各列的缺失率:
1
2
3
4
# 计算各列的缺失率,并保留两位小数
res = round((row.isnull().sum() / len(row) * 100), 2)
row = pd.DataFrame({'列名': res.index, '缺失值占比': res.values})
print(row)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
            列名  缺失值占比
0 ListingId 0.0
1 借款金额 0.0
2 借款期限 0.0
3 借款利率 0.0
4 借款成功日期 0.0
5 初始评级 0.0
6 借款类型 0.0
7 是否首标 0.0
8 年龄 0.0
9 性别 0.0
10 手机认证 0.0
11 户口认证 0.0
12 视频认证 0.0
13 学历认证 0.0
14 征信认证 0.0
15 淘宝认证 0.0
16 历史成功借款次数 0.0
17 历史成功借款金额 0.0
18 总待还本金 0.0
19 历史正常还款期数 0.0
20 历史逾期还款期数 0.0
21 我的投资金额 0.0
22 当前到期期数 0.0
23 当前还款期数 0.0
24 已还本金 0.0
25 已还利息 0.0
26 待还本金 0.0
27 待还利息 0.0
28 标当前逾期天数 0.0
29 标当前状态 0.0
30 上次还款日期 2.0
31 上次还款本金 2.0
32 上次还款利息 2.0
33 下次计划还款日期 60.0
34 下次计划还款本金 60.0
35 下次计划还款利息 60.0
36 recorddate 0.0
  • 计算总的缺失率:
1
2
3
4
5
6
7
8
9
10
# 假设df是已经加载的DataFrame
df = pd.read_csv('./LCIS.csv') # 示例代码,根据实际路径加载

# 计算至少含有一个空值的行数
rows_with_na = df.isnull().any(axis=1).sum()

# 计算总缺失率,这里的“总缺失”是指含有至少一个空值的行占总行数的比例
total_missing_rate = round((rows_with_na / len(df) * 100), 2)

print(f"总缺失率: {total_missing_rate}%")
1
总缺失率: 45.15%

删除含有空值的行或列

使用 dropna() 方法可以根据不同的需求删除含有空值的行或列。

DataFrame.dropna 参数说明:
  • axis: 控制删除含有缺失值的行或列。默认值为 0,意味着删除任何含有缺失值的行。如果设置为 1,则删除任何含有缺失值的列。

  • how: 定义了行或列被删除的条件。默认为 'any',表示如果行或列中存在任何缺失值,就将其删除。如果设置为 'all',则只有当行或列中的所有值都是缺失值时,才删除该行或列。

  • thresh: 指定一个行或列中非缺失值的最小数量,只有当非缺失值的数量达到这个阈值时,该行或列才会被保留。

  • subset: 用于指定一个列的子集来检查缺失值。这可以是单个列名,或者是多个列名组成的列表。只有在这个子集中检查到缺失值时,相应的行或列才会根据how参数的设置被删除。

  • inplace: 用于指定是否在原地修改DataFrame。如果设置为True,则原地修改DataFrame并返回None;如果设置为False(默认),则返回修改后的新DataFrame,原DataFrame不变。

  • 删除含有任何空值的行:

1
row.dropna(axis=0, inplace=True)
  • 删除含有任何空值的列:
1
row.dropna(axis=1, inplace=True)

填充空值

在很多情况下,直接删除含有空值的数据可能会导致信息的大量丢失,特别是在数据量不是很大的情况下。此时,填充空值成为了一种更好的选择。

  • 使用固定值填充所有空值:
1
2
# 使用0填充所有空值
row.fillna(0, inplace=True)
  • 针对特定列使用不同的填充值:
1
2
# 以1234填充'下次计划还款日期'列的空值
row['下次计划还款日期'].fillna(1234, inplace=True)
  • 使用列的统计值(均值、中位数、众数)填充空值:
1
2
3
4
5
6
7
8
9
10
11
# 使用均值填充
mean_val = row['下次计划还款利息'].mean()
row['下次计划还款利息'].fillna(mean_val, inplace=True)

# 使用中位数填充
median_val = row['下次计划还款利息'].median()
row['下次计划还款利息'].fillna(median_val, inplace=True)

# 使用众数填充(注意:众数可能返回多个值)
mode_val = row['下次计划还款利息'].mode()[0] # 选取第一个众数
row['下次计划还款利息'].fillna(mode_val, inplace=True)

错误数据清洗

在数据处理和分析中,清洗数据是一项基础而重要的任务,用于修正或删除数据集中的错误或不一致的数据。Pandas 是一个强大的 Python 数据分析库,它提供了多种方法来清洗错误数据。

替换错误数据

直接替换特定错误数据

如果已知特定数据项错误,可以直接替换它。例如,如果我们知道某个人的年龄被错误地录入为12345,而正确的年龄应为30,可以直接修改这个值:

1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd

# 创建DataFrame
person = {
"name": ['Google', 'Runoob', 'Taobao'],
"age": [50, 40, 12345] # 12345 是错误的年龄数据
}
df = pd.DataFrame(person)

# 直接替换错误数据
df.loc[2, 'age'] = 30 # 将年龄12345改为30

print(df)

基于条件的批量替换

在某些情况下,我们可能需要根据条件批量替换数据。例如,将所有大于120岁的年龄替换为120岁:

1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd

person = {
"name": ['Google', 'Runoob', 'Taobao'],
"age": [50, 200, 12345]
}
df = pd.DataFrame(person)

# 条件替换
df.loc[df['age'] > 120, 'age'] = 120

print(df)

删除错误数据

有时,与其修正错误的数据,不如直接将其删除。例如,删除年龄大于120岁的记录:

1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd

person = {
"name": ['Google', 'Runoob', 'Taobao'],
"age": [50, 40, 12345] # 12345 是错误的年龄数据
}
df = pd.DataFrame(person)

# 删除错误数据
df = df[df['age'] <= 120]

print(df)

数据格式错误处理

假设我们有一个包含日期和持续时间的数据集,但日期的格式不统一,这可能会导致分析时出现问题。以下是如何使用 Pandas 来解决这一问题的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd

# 假设数据集中的日期格式不统一,第三个日期格式错误
data = {
"Date": ['2020/12/01', '2020/12/02', '20201226'], # 第三个日期格式与其他两个不同
"Duration": [50, 40, 45]
}

# 使用字典创建 DataFrame
df = pd.DataFrame(data, index=["day1", "day2", "day3"])

# 将日期列的格式统一转换为 datetime 格式
df['Date'] = pd.to_datetime(df['Date'], errors='coerce', format='%Y/%m/%d')

print(df)
代码解析
  1. 导入 Pandas 库:首先,我们需要导入 Pandas 库,这是进行数据分析和数据清洗的基础。
  2. 创建 DataFrame:我们通过传递一个包含数据的字典(包括不一致的日期格式)来创建一个 DataFrame。这个 DataFrame 包括一个日期列和一个持续时间列。
  3. 转换日期格式:使用 pd.to_datetime() 方法将日期列转换为统一的 datetime 格式。这个方法非常强大,能够自动识别和转换多种日期格式。如果存在无法识别的格式,errors='coerce' 参数会将这些无法转换的日期替换为 NaT (时间戳数据的缺失值)。format='%Y/%m/%d' 参数是尝试按照这种格式解析日期,但不一定所有日期都能完全匹配此格式,故 errors='coerce' 在这里起着兜底的作用。
扩展和改进
  • 处理转换错误:在转换过程中,如果存在无法识别的日期格式,我们可以通过 errors='coerce' 参数来处理这些错误,将它们转换为 NaT,然后根据需要进行进一步处理,比如填充缺失值或者删除包含缺失值的行。
  • 格式化输出:在完成日期格式的统一后,我们还可以根据需要对日期进行格式化,比如将所有日期转换为特定的字符串格式。
  • 其他数据清洗任务:除了解决日期格式问题外,数据清洗可能还包括诸如删除重复值、处理缺失值、数据类型转换等任务。Pandas 提供了丰富的函数和方法来处理这些问题,比如 drop_duplicates()fillna()replace() 方法。

数据统计和运算是数据分析的基础,它涉及到对数据集进行概括性描述和数学计算的过程。Pandas 是一个强大的 Python 数据分析库,提供了一系列方便的数据统计和运算工具,帮助我们快速对数据进行处理和分析。以下是一些使用 Pandas 进行数据统计和运算的常用方法及其应用示例。

数据统计和运算

数据统计和运算是数据分析的基础,它涉及到对数据集进行概括性描述和数学计算的过程。Pandas 是一个强大的 Python 数据分析库,提供了一系列方便的数据统计和运算工具,帮助我们快速对数据进行处理和分析。以下是一些使用 Pandas 进行数据统计和运算的常用方法及其应用示例。

最大值和最小值:max()min()

1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd

# 读取数据
df = pd.read_csv("./LCIS.csv")

# 获取'借款金额'列的最大值
max_value = df['借款金额'].max()

# 获取'借款金额'列的最小值
min_value = df['借款金额'].min()

print("最大借款金额:", max_value)
print("最小借款金额:", min_value)

这段代码展示了如何读取一个 CSV 文件,并计算某一列(例如“借款金额”)的最大值和最小值。

非缺失值的数量:count()

df.count(axis=0, level=None, numeric_only=False)

  • axis:指定计算的方向,0 表示按列计算,1 表示按行计算,默认为 0。
  • level:用于 MultiIndex 的级别,在多层索引 DataFrame 中指定要计算的级别。
  • numeric_only:布尔值,表示是否只计算数值型列(int、float)的非缺失值,默认为 False,表示计算所有列的非缺失值数量。
1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd

df = pd.read_csv("./LCIS.csv")

# 计算每列的非缺失值数量
column_non_missing_count = df.count()

# 计算每行的非缺失值数量
row_non_missing_count = df.count(axis=1)

print(column_non_missing_count)
print(row_non_missing_count)

此代码展示了如何计算 DataFrame 中每列或每行的非缺失值(非 NaN 值)的数量。可以通过设置 axis 参数为 0(默认)计算每列的非缺失值数量,或设置为 1 计算每行的非缺失值数量。

求和与累加:sum()cumsum()

1
2
3
4
5
6
7
# 求和
total = df['借款金额'].sum()
print("借款金额总和:", total)

# 累加
df['累计借款金额'] = df['借款金额'].cumsum()
print(df)

这部分代码用于计算特定列的总和(sum())和累加值(cumsum())。cumsum() 方法在原有数据的基础上添加了一个累加列,显示到当前行为止的累计总和。

排序:sort_values()sort_index()

按列值排序

1
2
3
4
5
# 按照'借款金额'列的值进行升序排序
df.sort_values('借款金额', inplace=True)

# 根据'借款金额'进行升序排序,'年龄'进行降序排序
df.sort_values(['借款金额', '年龄'], ascending=[True, False], inplace=True)

这些例子展示了如何按照一个或多个列的值对 DataFrame 进行排序。可以通过 ascending 参数控制排序的方向(升序或降序)。

按索引排序

1
2
# 按照索引进行排序
df.sort_index(inplace=True)

如果需要根据行索引进行排序,可以使用 sort_index() 方法。这在重置数据顺序时特别有用。

扩展

  • 计算缺失值:利用 count() 方法的结果可以间接计算出某列或整个 DataFrame 的缺失值数量。例如,DataFrame 总行数减去 count() 方法返回的非缺失值数量即为缺失值数量。
  • 设置列名:当从函数返回一个 Series 或需要更改 DataFrame 的列名时,可以直接通过修改 columns 属性或者在创建 DataFrame 时指定列名。
  • 读取部分数据:对于大型数据集,可以使用 pd.read_csv() 函数的 nrows 参数仅读取前 N 行数据,有助于快速测试代码或减少内存消耗。

数据分组和聚合

df.groupby(column_name)

groupby() 方法是用来对数据进行分组的,特别是当你想要按照某个(或某些)列的值对整个数据集进行分组时。分组后,可以对每个分组应用聚合函数,比如求和、平均、最大值和最小值等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 按照'年龄'列分组,并计算每个年龄组的数量
age_group_count = df.groupby('年龄').count()
print(age_group_count)

# 只统计不同年龄组的'借款金额'总和
age_group_loan_sum = df.groupby('年龄')['借款金额'].sum()
print(age_group_loan_sum)

# 计算每个年龄组的'借款金额'的最大值、最小值和平均值
age_group_loan_max = df.groupby('年龄')['借款金额'].max()
age_group_loan_min = df.groupby('年龄')['借款金额'].min()
age_group_loan_mean = df.groupby('年龄')['借款金额'].mean()
print(age_group_loan_max)
print(age_group_loan_min)
print(age_group_loan_mean)

# 按照'性别'分组,并计算'借款金额'的最大值、最小值和平均值
gender_group_loan_max = df.groupby('性别')['借款金额'].max()
gender_group_loan_min = df.groupby('性别')['借款金额'].min()
gender_group_loan_mean = df.groupby('性别')['借款金额'].mean()
print(gender_group_loan_max)
print(gender_group_loan_min)
print(gender_group_loan_mean)

df.aggregate(function_name)

aggregate() 方法允许你对整个 DataFrame 或某些选定的列应用一个或多个聚合函数。

1
2
3
4
5
6
7
# 对整个 DataFrame 应用多个聚合函数
agg_results = df.aggregate(['sum', 'mean'])
print(agg_results) # 可能会报错,因为字符类型的列不能进行数学计算

# 对指定列应用聚合函数
agg_specific = df.aggregate({'借款金额': 'sum', '年龄': 'mean'})
print(agg_specific)

如果数据集中包含非数值类型(如字符串),直接应用 summean 会导致错误。为了避免这种情况,你应该指定要应用聚合函数的列,或者通过 numeric_only=True 参数来排除非数值列。

df.pivot_table(values, index, columns, aggfunc)

pivot_table() 方法是用来创建透视表的,这在你想要对数据进行多维度的分组聚合时特别有用。

1
2
3
# 创建透视表,将'性别'作为索引,对'借款金额'进行求和
gender_loan_pivot_table = df.pivot_table(values='借款金额', index='性别', aggfunc='sum')
print(gender_loan_pivot_table)

在透视表中,values 参数是你想要聚合的列,index 参数是你想要作为行索引的列,columns 参数(可选)是你想要作为列索引的列,aggfunc 是定义聚合函数的参数。

这些方法不仅可以帮助你从数据集中提取有意义的统计信息,还可以根据你的特定需求进行高度定制化的数据处理和分析。通过使用这些工具,你可以轻松地对数据进行分组和聚合,从而提取出关键的洞见。

案例

数据导入与演示

1
2
3
4
5
6
7
8
9
import pandas as pd

df = pd.read_csv('./LCIS.csv')
# 显示所有的数据
# pd.set_option('display.max_rows', None) # 显示所有行
pd.set_option('display.max_columns', None) # 显示所有列
# pd.set_option('expand_frame_repr', False) # 不自动换行

print(df)
        ListingId   借款金额  借款期限  借款利率      借款成功日期 初始评级 借款类型 是否首标  年龄 性别   手机认证  \
0         1693100   3629     6  12.0   2015/1/28   AA   普通    否  31  男   成功认证   
1         1713229   3000    12  12.0   2015/1/30   AA   普通    是  24  男   成功认证   
2         1904026   3629    12  12.0    2015/3/7   AA   普通    否  27  男   成功认证   
3         2158281   3919    12  18.0   2015/4/14    C   普通    否  28  男   成功认证   
4         2257194  14000    12  18.0   2015/4/23    C   普通    否  46  男   成功认证   
...           ...    ...   ...   ...         ...  ...  ...  ...  .. ..    ...   
292534   29087298   7193    12  22.0  2016/12/29    C   普通    否  48  男   成功认证   
292535   29995173   3241    12  22.0    2017/1/5    C   其他    否  25  女   成功认证   
292536   30355195   3004    12  22.0    2017/1/8    C   其他    否  28  男  未成功认证   
292537   30649717   2082    12  22.0   2017/1/11    C   普通    否  52  男   成功认证   
292538   31620657  10000    12  22.0   2017/1/20    D   普通    是  24  女  未成功认证   

         户口认证   视频认证   学历认证   征信认证   淘宝认证  历史成功借款次数  历史成功借款金额     总待还本金  \
0       未成功认证  未成功认证  未成功认证  未成功认证  未成功认证       1.0    3000.0   1313.46   
1       未成功认证  未成功认证  未成功认证  未成功认证  未成功认证       0.0       0.0      0.00   
2       未成功认证  未成功认证  未成功认证  未成功认证  未成功认证       1.0    3000.0    878.58   
3        成功认证  未成功认证  未成功认证  未成功认证  未成功认证       4.0   13800.0   6523.11   
4       未成功认证  未成功认证  未成功认证  未成功认证  未成功认证      11.0   54840.0  11491.04   
...       ...    ...    ...    ...    ...       ...       ...       ...   
292534  未成功认证  未成功认证  未成功认证  未成功认证  未成功认证       1.0    3500.0    306.54   
292535  未成功认证  未成功认证   成功认证  未成功认证  未成功认证       1.0    5000.0   1758.28   
292536  未成功认证  未成功认证  未成功认证  未成功认证  未成功认证       1.0    2200.0   1495.67   
292537  未成功认证  未成功认证  未成功认证  未成功认证  未成功认证       6.0   22064.0   5747.77   
292538  未成功认证  未成功认证   成功认证  未成功认证  未成功认证       0.0       0.0      0.00   

        历史正常还款期数  历史逾期还款期数  我的投资金额  当前到期期数  当前还款期数    已还本金   已还利息    待还本金  \
0              2         2     200       6       6  200.00   7.00    0.00   
1              0         0     500      12       9  500.00  29.80    0.00   
2              5         0     500      12      12  500.00  33.04    0.00   
3             25         0     100      12       2  100.00   1.72    0.00   
4             53         0     100      12       0    0.00   0.00  100.00   
...          ...       ...     ...     ...     ...     ...    ...     ...   
292534        11         0      55       2       2    8.35   1.94   46.65   
292535         3         3      50       1       1    3.76   0.91   46.24   
292536         4         0      50       1       1    3.76   0.91   46.24   
292537        39         6      55       1       1    4.13   1.01   50.87   
292538         0         0      73       1       1    5.49   1.34   67.51   

        待还利息  标当前逾期天数  标当前状态      上次还款日期  上次还款本金  上次还款利息   下次计划还款日期  下次计划还款本金  \
0       0.00        0    已还清   2015/7/28   34.20    0.30        NaN       NaN   
1       0.00        0    已还清  2015/10/19  173.39    1.05        NaN       NaN   
2       0.00        0    已还清    2016/3/6   44.04    0.38        NaN       NaN   
3       0.00        0    已还清   2015/5/19   92.34    0.22        NaN       NaN   
4       9.92      589    逾期中         NaN     NaN     NaN  2015/5/23      7.66   
...      ...      ...    ...         ...     ...     ...        ...       ...   
292534  4.83        0  正常还款中   2017/2/26    4.22    0.93  2017/3/28      4.29   
292535  5.24        0  正常还款中    2017/2/9    3.76    0.91   2017/3/5      3.83   
292536  5.24        0  正常还款中    2017/2/8    3.76    0.91   2017/3/8      3.83   
292537  5.76        0  正常还款中   2017/2/10    4.13    1.01  2017/3/10      4.22   
292538  7.64        0  正常还款中   2017/2/20    5.49    1.34  2017/3/20      5.59   

        下次计划还款利息  recorddate  
0            NaN  2016/12/31  
1            NaN  2016/12/31  
2            NaN  2016/12/31  
3            NaN  2016/12/31  
4           1.50  2016/12/31  
...          ...         ...  
292534      0.86   2017/2/28  
292535      0.85   2017/2/28  
292536      0.85   2017/2/28  
292537      0.93   2017/2/28  
292538      1.24   2017/2/28  

[292539 rows x 37 columns]

总缺失率

1
2
3
4
5
6
7
# 计算至少含有一个空值的行数
rows_with_na = df.isnull().any(axis=1).sum()

# 计算总缺失率,这里的“总缺失”是指含有至少一个空值的行占总行数的比例
total_missing_rate = round((rows_with_na / len(df) * 100), 2)

print(f"总缺失率: {total_missing_rate}%")
总缺失率: 45.15%

手机认证用户借贷笔数

1
2
3
4
# 手机认证借贷笔数 
loan_phone = df[df['手机认证'] == '成功认证'].shape[0]

print(loan_phone)
153453

户门认证用户借贷情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 筛选户口认证为“成功认证”的用户
df_hukou_success = df[df['户口认证'] == '成功认证']

# 计算平均借款金额
avg_loan_amount_hukou_success = df_hukou_success['借款金额'].mean()

# 计算平均借款期限
avg_loan_duration_hukou_success = df_hukou_success['借款期限'].mean()

# 计算平均借款利率
avg_interest_rate_hukou_success = df_hukou_success['借款利率'].mean()

# 计算平均年龄
avg_age_hukou_success = df_hukou_success['年龄'].mean()

print(f"户口认证成功的用户平均借款金额: {avg_loan_amount_hukou_success:.2f}")
print(f"户口认证成功的用户平均借款期限: {avg_loan_duration_hukou_success:.2f} 个月")
print(f"户口认证成功的用户平均借款利率: {avg_interest_rate_hukou_success:.2f}%")
print(f"户口认证成功的用户平均年龄: {avg_age_hukou_success:.2f} 岁")
户口认证成功的用户平均借款金额: 36955.01
户口认证成功的用户平均借款期限: 10.04 个月
户口认证成功的用户平均借款利率: 17.15%
户口认证成功的用户平均年龄: 31.42 岁

征信认证用户借贷情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 筛选出征信认证为成功认证的行
df_credit_approved = df[df['征信认证'] == '成功认证']

# 计算平均借款金额
avg_loan_amount_credit_approved = df_credit_approved['借款金额'].mean()

# 计算平均借款期限
avg_loan_duration_credit_approved = df_credit_approved['借款期限'].mean()

# 计算平均借款利率
avg_interest_rate_credit_approved = df_credit_approved['借款利率'].mean()

# 计算平均年龄
avg_age_credit_approved = df_credit_approved['年龄'].mean()

print(f"征信认证成功的用户平均借款金额: {avg_loan_amount_credit_approved:.2f}")
print(f"征信认证成功的用户平均借款期限: {avg_loan_duration_credit_approved:.2f} 个月")
print(f"征信认证成功的用户平均借款利率: {avg_interest_rate_credit_approved:.2f}%")
print(f"征信认证成功的用户平均年龄: {avg_age_credit_approved:.2f} 岁")
征信认证成功的用户平均借款金额: 9138.00
征信认证成功的用户平均借款期限: 10.59 个月
征信认证成功的用户平均借款利率: 18.27%
征信认证成功的用户平均年龄: 29.79 岁

性别认证用户还款情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 确保性别列存在并且不为空
df_with_gender = df[df['性别'].notna()]

# 按性别分组,并计算各项指标的平均值
repayment_status = df_with_gender.groupby('性别').agg({
'借款金额': 'mean',
'历史成功借款次数': 'mean',
'历史逾期还款期数': 'mean',
'总待还本金': 'mean'
}).reset_index()

# 重命名列以更清晰地表示它们的内容
repayment_status.columns = ['性别', '平均借款金额', '平均历史成功借款次数', '平均历史逾期还款期数', '平均待还本金']

print(repayment_status)
  性别       平均借款金额  平均历史成功借款次数  平均历史逾期还款期数       平均待还本金
0  女  6896.238214    2.651062   17.975806  4706.631430
1  男  9385.546621    2.547655   18.575870  4388.516472

不同性别用户还款占比情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 定义正常还款状态
normal_repayment_statuses = ['已还清', '正常还款中']

df_per_gender = df

# 创建一个新列,用于标记是否正常还款
df_per_gender['是否正常还款'] = df_per_gender['标当前状态'].apply(lambda x: '正常还款' if x in normal_repayment_statuses else '未还清')

# 计算每个性别的还款占比
repayment_by_gender = df_per_gender.groupby('性别')['是否正常还款'].value_counts(normalize=True).unstack().fillna(0)

# 将占比转换为百分比
repayment_by_gender_percentage = repayment_by_gender * 100

print(repayment_by_gender_percentage)
是否正常还款       未还清       正常还款
性别                         
女       3.216114  96.783886
男       3.948184  96.051816

学历认证用户还款情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
df_sty_auth = df[df['学历认证'] == '成功认证']

# 分析学历认证用户的还款情况
# 计算历史正常还款期数和历史逾期还款期数的平均值
avg_normal_re = df_sty_auth['历史正常还款期数'].mean()
avg_dishor_re = df_sty_auth['历史逾期还款期数'].mean()

# 计算已还本金、已还利息的总和
org_done_total = df_sty_auth['已还本金'].sum()
fee_done_total = df_sty_auth['已还利息'].sum()

print(f"学历认证用户平均历史正常还款期数: {avg_normal_re}")
print(f"学历认证用户平均历史逾期还款期数: {avg_dishor_re}")
print(f"学历认证用户总已还本金: {org_done_total}")
print(f"学历认证用户总已还利息: {fee_done_total}")
学历认证用户平均历史正常还款期数: 78.98516016370341
学历认证用户平均历史逾期还款期数: 13.045753352616355
学历认证用户总已还本金: 6445238.179999999
学历认证用户总已还利息: 499930.52000000014

学历认证用户还款占比情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 筛选学历认证成功的用户
df_education_certified = df[df['学历认证'] == '成功认证']

# 计算各状态下的用户数量
status_counts = df_education_certified['标当前状态'].value_counts()

# 计算总数,用于计算比例
total_certified = df_education_certified.shape[0]

# 计算占比
status_proportions = status_counts / total_certified

# 打印结果
print(status_proportions)
标当前状态
正常还款中    0.692517
已还清      0.279435
逾期中      0.027097
0        0.000620
0.7      0.000040
2.35     0.000020
0.62     0.000013
5.76     0.000013
1.16     0.000013
1.07     0.000013
4.73     0.000007
1.33     0.000007
0.2      0.000007
2.82     0.000007
0.4      0.000007
0.34     0.000007
2.95     0.000007
3.15     0.000007
2.6      0.000007
2.66     0.000007
5.5      0.000007
2.65     0.000007
0.11     0.000007
5.81     0.000007
1.17     0.000007
1.74     0.000007
0.77     0.000007
4.92     0.000007
2.46     0.000007
0.38     0.000007
6.47     0.000007
1.78     0.000007
0.76     0.000007
3.42     0.000007
0.13     0.000007
1.51     0.000007
0.73     0.000007
0.48     0.000007
3.76     0.000007
4.83     0.000007
0.49     0.000007
3.39     0.000007
Name: count, dtype: float64

不同年龄段用户借款统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 定义年龄段
bins = [18, 25, 35, 45, 55, 65, 75]
labels = ['18-24', '25-34', '35-44', '45-54', '55-64', '65-74']
age_df = df
age_df['年龄段'] = pd.cut(age_df['年龄'], bins=bins, labels=labels, right=False)

# 计算每个年龄段的借款统计
age_group_stats = df.groupby('年龄段').agg({
'借款金额': ['sum', 'mean', 'count']
})

age_group_stats.columns = ['借款金额总和', '平均借款金额', '借款次数']
age_group_stats = age_group_stats.reset_index()

# 显示结果
print(age_group_stats)
     年龄段      借款金额总和         平均借款金额    借款次数
0  18-24   296139563    4755.963239   62267
1  25-34  1554537910    8642.275290  179876
2  35-44   527141564   12732.272934   41402
3  45-54   106455104   12088.928458    8806
4  55-64     4524174   24722.262295     183
5  65-74     2500000  500000.000000       5

不同年龄段用户还款占比统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 添加年龄段分类
bins = [0, 24, 34, 44, 54, 100]
labels = ['<25', '25-34', '35-44', '45-54', '55+']
age_per_df = df
age_per_df['年龄段'] = pd.cut(age_per_df['年龄'], bins=bins, labels=labels, right=False)

# 计算每个年龄段的已还本金总额
repayment_by_age_group = df.groupby('年龄段')['已还本金'].sum()

# 计算总的已还本金以确定占比
total_repayment = df['已还本金'].sum()

# 计算占比
repayment_ratio = (repayment_by_age_group / total_repayment * 100).reset_index()

# 设置新的列名以改进展示
repayment_ratio.columns = ['年龄段', '已还本金占比(%)']

# 输出结果
print(repayment_ratio)
     年龄段  已还本金占比(%)
0    <25  14.278337
1  25-34  62.234454
2  35-44  18.792848
3  45-54   4.536181
4    55+   0.158180

数据分析常用函数

数据筛选

如果是筛选行列的话,通常有以下几种方法:
有时我们需要按条件选择部分列、部分行,一般常用的方法有:

操作 语法 返回结果
选择列 df[col] Series
按索引选择行 df.loc[label] Series
按数字索引选择行 df.iloc[loc] Series
使用切片选择行 df[:5] DataFrame
用表达式筛选行[3] df[bool_vec] DataFrame

除此以外,还有很多方法/函数可以用于“数据筛选”

数据预览

对于探索性数据分析来说,做数据分析前需要先看一下数据的总体概况。

  • info()方法用来查看数据集信息
  • describe()方法将返回描述性统计信息,这两个函数大家应该都很熟悉了。
  • describe方法默认只给出数值型变量的常用统计量,要想对DataFrame中的每个变量进行汇总统计,可以将其中的参数include设为allhead()方法显示数据集的前n行
  • tail() 方法显示数据集的后n行。
  • sample()方法随机看N行的数据。
1
df.sample(3)
  • df.dtypes 检查数据中各列的数据类型。
  • df.columns 查看所有的列名 。
1
2
df.dtypes
df.columns
1
Index(['日期', '销量'], dtype='object')

.dfshape() 获得数据集的大小(长宽)。

1
df.shape
1
(5, 2)
  • len(df)可以查看总个数
  • df.count()则可以查看有效个数,不包含无效值(Nan)

缺失值与重复值

Pandas清洗数据时,判断缺失值一般采用isnull()方法。
isnull().any()会判断哪些”列”存在缺失值。
isnull().sum()用于将列中为空的个数统计出来。

1
df.isnull().any()
1
2
3
日期 False
销量 True
dtype: bool

发现“销量”这列存在缺失值后,处理办法要么删除dropna() ,要么填充fillna()

1
df.fillna(50)
  • Pandas清洗数据时,判断重复值一般采用duplicated()方法。
  • 如果想要直接删除重复值,可以使用drop_duplicates() 方法。

数据值操作

在数值数据操作中,apply()函数的功能是将一个自定义函数作用于DataFrame的行或者列;applymap()函数的功能是将自定义函数作用于DataFrame的所有元素。

1
df["数量"].apply(lambda x: x+1)

数据批量替换的情况,replace()是很好的解决方法。它既支持替换全部或者某一行,也支持替换指定的某个或指定的多个数值(用字典的形式)。还可以使用正则表达式替换。

1
df["编号"].replace(r'BA.$', value='NEW', regex=True, inplace = True)

调⽤rank()⽅法可以实现数据排名。

1
df["排名"] = df.rank(method="dense").astype("int")

rank()⽅法中的method参数,它有5个常⽤选项,可以帮助我们实现不同情况下的排名。

唯一值,unique()是以数组形式返回列的所有唯一值,而nunique()返回的是唯一值的个数。

1
2
df["gender"].unique()
df["gender"].nunique()

clip()方法,用于对超过或者低于某些数的数值进行截断[1],来保证数值在一定范围。比如每月的迟到天数一定是在0-31天之间。

1
df["迟到天数"] = df["迟到天数"].clip(0,31)

行/列操作

rename()重命名用于更改行列的标签,即行列的索引。可以传入一个字典或者一个函数。在数据预处理中,比较常用。

1
df.rename(columns={'mark': 'sell'}, inplace=True)

数据清洗时,会将带空值的行删除,此时DataFrame或Series类型的数据不再是连续的索引,可以使用reset_index()重置索引。

1
df.reset_index(drop=True)

删除行列,可以使用drop()

1
df.drop(columns=["mark"])

行列转置,我们可以使用T属性获得转置后的DataFrame。

1
df.T

melt()方法可以将宽表转长表,即表格型数据转为树形数据。

1
df.melt(id_vars="姓名", var_name="科目", value_name="成绩")

pivot()方法可以将长表转宽表,即树形数据转为表格型数据。

1
df.pivot(index='姓名', columns='科目', values='成绩')

数据分组与数据透视表更是一个常见的需求,groupby()方法可以用于数据分组。

1
df.groupby("科目").mean()

pivot_table()数据透视表

数值数据统计运算

在对数值型的数据进行统计运算时,除了有算术运算、比较预算还有各种常见的汇总统计运行函数,具体如下表所示

函数方法 用法释义
count 非NaN数据项计数
sum 求和
mean 平均值
median 中位数
mode 众数
max 最大值
min 最小值
std 标准差
var 方差
quantile 分位数
skew 返回偏态系数
kurt 返回峰态系数

累加cumsum()

1
df["累计销量"] = df["销量"].cumsum()

文本数据操作

在对文本型的数据进行处理时,我们会大量应用字符串的函数,来实现对一列文本数据进行操作。

函数方法 用法释义
cat 字符串的拼接
contains 判断某个字符串是否包含给定字符
startswith/endswith 判断某个字符串是否以…开头/结尾
get 获取指定位置的字符串
len 计算字符串长度
upper、lower 英文大小写转换
pad/center 在字符串的左边、右边或左右两边添加给定字符
repeat 重复字符串几次
slice_replace 使用给定的字符串,替换指定的位置的字符
split 分割字符串,将一列扩展为多列
strip、rstrip、lstrip 去除空白符、换行符
findall 利用正则表达式,去字符串中匹配,返回查找结果的列表
extract、extractall 接受正则表达式,抽取匹配的字符串(一定要加上括号)
  • 标题: Pandas
  • 作者: Yiuhang Chan
  • 创建于 : 2018-11-12 10:23:47
  • 更新于 : 2024-03-19 17:53:53
  • 链接: https://www.yiuhangblog.com/2018/11/12/20181112Pandas/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
此页目录
Pandas