python Dataframe操作
目录:
一、在Dataframe的最后插入一列
二、指定Dataframe一列的数据类型
三、遍历Dataframe的每一行,为什么修改行里的数据不会同步修改到Dataframe中
四、Dataframe删除重复的行
五、Dataframe删除列
六、Dataframe重排索引
七、给Dataframe增加一列,每次遍历给该新增列中的元素赋值
八、将字典嵌套列表转换为Dataframe
九、Dataframe中at、loc、iloc的区别
一、在dataframe的最后插入一列
如果想在 DataFrame
的最后插入一列,可以通过以下几种方法来实现。
方法 1:直接赋值新列
可以通过直接为 DataFrame
赋值新列,添加一个新列来将其插入到最后。
import pandas as pd
# 示例 DataFrame
df = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6]
})
# 新列数据
new_column = [7, 8, 9]
# 在 DataFrame 的最后插入新列
df['C'] = new_column
# 打印结果
print(df)
输出:
A B C
0 1 4 7
1 2 5 8
2 3 6 9
在这个例子中,通过直接赋值为列 'C'
插入了新列。
如果需要将新的列数据设置为某个常数值,可以直接赋值为常数。
示例(常数值):
df['D'] = 10 # 将新列 D 的所有值都设置为 10
如果要向DataFrame的最后添加一列,通常你只需要保证新列的长度与现有DataFrame的行数相匹配。
方法 2:使用 insert
方法
虽然 insert
方法通常用于在指定位置插入列,但你也可以将其用来在最后插入列。为了插入到最后,只需要指定位置为 len(df.columns)
。
# 使用 insert 在最后插入新列
df.insert(len(df.columns), 'C', new_column)
# 打印结果
print(df)
输出:
A B C
0 1 4 7
1 2 5 8
2 3 6 9
解释:
df.insert(len(df.columns), 'C', new_column)
中,len(df.columns)
表示列的总数,表示我们要把新列插入到最后一个位置。'C'
是新列的列名,new_column
是列的数据。方法 3:使用 assign
方法
你还可以使用 assign
方法来添加新列。该方法会返回一个新的 DataFrame
,因此你需要将结果重新赋值给原 DataFrame
# 使用 assign 添加新列
df = df.assign(C=new_column)
# 打印结果
print(df)
输出:
A B C
0 1 4 7
1 2 5 8
2 3 6 9
assign
方法会返回一个新的 DataFrame
,所以它的行为类似于直接赋值,只不过它更适合链式操作。
二、指定Dataframe一列的数据类型
使用astype() 手动指定列的数据类型
df['A'] = df['A'].astype(str)
df['B'] = df['B'].astype(int)
df['C'] = df['C'].astype(object)
三、遍历Dataframe的每一行,为什么修改行里的数据不会同步修改到Dataframe中
在 Pandas 中,遍历 DataFrame 的每一行时,如果直接修改行中的数据,修改的内容不会自动同步到原始 DataFrame。这是因为当你遍历行时,实际上你得到的是该行的一个副本,而不是对 DataFrame 本身的引用。修改副本不会影响原始的 DataFrame。
为了更清晰地理解,来看以下两个方面的详细解释:
1. 通过 .iterrows()
遍历行
import pandas as pd
data = {'A': [1, 2, 3], 'B': [4, 5, 6]}
df = pd.DataFrame(data)
for index, row in df.iterrows():
row['A'] = row['A'] + 1 # 修改行副本中的值
print(df)
输出:
A B
0 1 4
1 2 5
2 3 6
这里,df.iterrows()
返回的是每一行的 副本,你修改的是副本中的 row
对象,而不是原始 DataFrame 中的值。因此,修改后的值不会同步回 df
。
2. 为什么修改不会反映到 DataFrame?
在 .iterrows()
中,每一行返回的是一个 Series
对象,它是原 DataFrame 中这一行数据的副本(而不是引用)。这意味着对 row
的修改不会影响到原始的 DataFrame。Python 中的赋值操作(如 row['A'] = row['A'] + 1
)会修改副本的内容,但不会修改原 DataFrame。
3. 解决方法:通过 .iloc[]
或 .loc[]
修改原 DataFrame
为了确保对 DataFrame 中的行修改是有效的,我们应该直接修改原 DataFrame 中的元素,而不是修改副本。可以通过 .iloc[]
或 .loc[]
进行修改。
示例 1: 使用 .iloc[]
import pandas as pd
data = {'A': [1, 2, 3], 'B': [4, 5, 6]}
df = pd.DataFrame(data)
for index, row in df.iterrows():
df.loc[index, 'A'] = row['A'] + 1 # 直接修改原 DataFrame
print(df)
输出:
A B
0 2 4
1 3 5
2 4 6
在这个例子中,我们使用 df.loc[index, 'A']
来直接修改原 DataFrame 中 A
列的值。
示例 2: 使用 .loc[]
import pandas as pd
data = {'A': [1, 2, 3], 'B': [4, 5, 6]}
df = pd.DataFrame(data)
for index, row in df.iterrows():
df.loc[index, 'A'] = row['A'] + 1 # 直接修改原 DataFrame
print(df)
总结:
.iterrows()
返回的是 DataFrame 行的副本,对副本的修改不会影响原 DataFrame。.loc[]
或 .iloc[]
来直接修改 DataFrame 中的元素。四、Dataframe删除重复的行
在 pandas
中删除 DataFrame
中的重复行,可以使用 drop_duplicates()
方法。以下是一些常见的用法示例:
1. 删除所有重复的行(基于所有列)
import pandas as pd
# 创建一个示例DataFrame
data = {'A': [1, 2, 2, 3, 3], 'B': [4, 5, 5, 6, 6]}
df = pd.DataFrame(data)
# 删除所有重复的行
df = df.drop_duplicates()
print(df)
2. 删除基于特定列的重复行
你可以指定要检查重复的列。如果只想基于某些列来删除重复的行,可以使用 subset
参数。
# 删除基于列 'A' 的重复行
df = df.drop_duplicates(subset=['A'])
print(df)
3. 保留第一次出现的行或最后一次出现的行
# 保留最后一次出现的重复行
df = df.drop_duplicates(keep='last')
print(df)
keep='first'
:默认值,保留第一次出现的行。keep='last'
:保留最后一次出现的行。keep=False
:删除所有重复的行。4. 使用 inplace=True
直接修改原始 DataFrame
如果不想创建一个新的 DataFrame
,可以使用 inplace=True
参数直接修改原始的 DataFrame
。
df.drop_duplicates(inplace=True)
总结:
drop_duplicates()
是删除重复行的主要方法。subset
参数指定某些列,keep
参数控制保留哪些重复行。五、Dataframe删除列
在 pandas
中删除 DataFrame
的列,可以使用 drop()
方法。以下是如何删除列的几种常见方法:
1. 删除单列或多列
import pandas as pd
# 创建一个示例DataFrame
data = {'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9]}
df = pd.DataFrame(data)
# 删除单列 'B'
df = df.drop('B', axis=1)
# 删除多列 'A' 和 'C'
df = df.drop(['A', 'C'], axis=1)
print(df)
2. 使用 inplace=True
参数
如果不想创建新的 DataFrame
,可以直接在原始 DataFrame
上删除列,使用 inplace=True
参数。
df.drop('B', axis=1, inplace=True)
3. 使用 del
关键字
如果你确定列名存在,可以使用 del
关键字来删除列。
del df['B']
4. 参数说明:
axis=1
表示按列删除。如果要按行删除,使用 axis=0
。inplace=True
会直接修改原始 DataFrame
,而不是返回一个新的 DataFrame
。六、Dataframe重拍索引
在 Pandas 中,你可以使用 reset_index()
和 set_index()
方法来重新排列 DataFrame 的索引。具体来说:
1. 重设索引(reset_index)
如果你想将当前的索引重置为默认的整数索引,并把原来的索引列转化为普通列,可以使用 reset_index()
。
import pandas as pd
# 创建一个简单的 DataFrame
data = {'A': [1, 2, 3], 'B': [4, 5, 6]}
df = pd.DataFrame(data, index=['a', 'b', 'c'])
# 重设索引
df_reset = df.reset_index()
print(df_reset)
输出:
index A B
0 a 1 4
1 b 2 5
2 c 3 6
默认情况下,reset_index()
会把旧的索引列添加为普通列,并为 DataFrame 创建新的默认整数索引。如果你不想把旧的索引列保留在 DataFrame 中,可以使用 drop=True
参数:
df_reset = df.reset_index(drop=True)
2. 设置新索引(set_index)
如果你想根据 DataFrame 中的一列或几列数据设置新的索引,可以使用 set_index()
。
# 设置 'A' 列作为新的索引
df_set = df.set_index('A')
print(df_set)
输出:
B
A
1 4
2 5
3 6
3. 重排序索引
如果你想对现有索引进行排序,可以使用 sort_index()
方法。例如:
# 按照索引排序
df_sorted = df.sort_index(ascending=False)
print(df_sorted)
输出:
A B
c 3 6
b 2 5
a 1 4
4. 多层索引(MultiIndex)中的重排
如果你的 DataFrame 使用了多层索引(MultiIndex
),你也可以通过 reset_index()
和 set_index()
来调整层级。
示例:设置多层索引
# 创建 MultiIndex DataFrame
arrays = [['a', 'a', 'b', 'b'], ['x', 'y', 'x', 'y']]
index = pd.MultiIndex.from_arrays(arrays, names=('letter', 'number'))
df_multi = pd.DataFrame({'value': [10, 20, 30, 40]}, index=index)
print(df_multi)
输出:
value
letter number
a x 10
y 20
b x 30
y 40
示例:重设 MultiIndex
# 重设索引
df_reset_multi = df_multi.reset_index()
print(df_reset_multi)
输出:
letter number value
0 a x 10
1 a y 20
2 b x 30
3 b y 40
七、给Dataframe增加一列,每次遍历给该新增列中的元素赋值
在 pandas
中给 DataFrame
增加一列,并且通过遍历给该列中的元素赋值,可以通过多种方式实现。你可以使用 iterrows()
或 apply()
等方法来遍历 DataFrame
的每一行,并对新增列进行赋值。
方法 1:使用 iterrows()
遍历
iterrows()
是一个迭代器,它可以逐行遍历 DataFrame
,返回每行的索引和数据。你可以在遍历过程中为新增列赋值。
import pandas as pd
# 示例 DataFrame
data = {
'Name': ['Alice', 'Bob', 'Charlie'],
'Age': [25, 30, 35]
}
df = pd.DataFrame(data)
# 增加一列 'NewColumn',初始为空
df['NewColumn'] = None
# 使用 iterrows() 遍历 DataFrame 并给 'NewColumn' 列赋值
for index, row in df.iterrows():
# 给新增列赋值
df.at[index, 'NewColumn'] = f"Value_{index}"
# df.loc[index, 'NewColumn'] = f"Value_{index}"
# 打印结果
print(df)
输出:
Name Age NewColumn
0 Alice 25 Value_0
1 Bob 30 Value_1
2 Charlie 35 Value_2
方法 2:使用 apply()
方法
apply()
方法通常比 iterrows()
更高效。如果你对每一行或每一列进行操作,可以使用 apply()方法
结合 lambda
函数来进行赋值。
示例:
import pandas as pd
# 示例 DataFrame
data = {
'Name': ['Alice', 'Bob', 'Charlie'],
'Age': [25, 30, 35]
}
df = pd.DataFrame(data)
# 使用 apply() 给 'NewColumn' 列赋值
df['NewColumn'] = df.apply(lambda row: f"Value_{row.name}", axis=1)
# 打印结果
print(df)
输出:
Name Age NewColumn
0 Alice 25 Value_0
1 Bob 30 Value_1
2 Charlie 35 Value_2
说明:
iterrows()
可以逐行遍历 DataFrame,但效率较低,尤其对于较大的数据集。apply()
是对每一行或每一列应用一个函数,通常会比 iterrows()
更高效。row.name
会返回当前行的索引,可以用来动态地为每一行生成值。方法 3:通过 for
循环直接赋值(适用于小型 DataFrame)
可以通过 for
循环直接遍历 DataFrame 的索引,并赋值。
示例:
import pandas as pd
# 示例 DataFrame
data = {
'Name': ['Alice', 'Bob', 'Charlie'],
'Age': [25, 30, 35]
}
df = pd.DataFrame(data)
# 增加一列 'NewColumn',初始为空
df['NewColumn'] = None
# 使用 for 循环给 'NewColumn' 列赋值
for i in range(len(df)):
df.loc[i, 'NewColumn'] = f"Value_{i}"
# 打印结果
print(df)
输出:
Name Age NewColumn
0 Alice 25 Value_0
1 Bob 30 Value_1
2 Charlie 35 Value_2
总结:
iterrows()
可以遍历每一行并逐一赋值。apply()
更为简洁且高效,尤其适合对每一行做操作。for
循环和 loc
也可以完成任务。选择合适的方法取决于你数据的规模和操作的复杂性。
八、将字典嵌套列表转换为Dataframe
如果你有一个字典嵌套列表,并且想将其转换为 pandas
的 DataFrame,通常的做法是将字典的每个键视作 DataFrame 的列,字典的值(如果是列表或其他可迭代对象)作为对应列的元素。
下面是一些常见的示例,展示如何将字典嵌套列表转换为 DataFrame
。
示例 1:字典嵌套列表(每个键对应一个列表)
有如下字典:
import pandas as pd
# 字典嵌套列表
data = {
'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9]
}
可以直接将其转换为 DataFrame:
df = pd.DataFrame(data)
print(df)
输出:
A B C
0 1 4 7
1 2 5 8
2 3 6 9
示例 2:字典嵌套列表(每个键对应一个字典)
如果你有一个字典嵌套字典的情况,每个值是一个字典(通常字典中的键是列名,值是列的值),可以通过将这个字典转换为 DataFrame 来实现:
data = {
'row1': {'A': 1, 'B': 4, 'C': 7},
'row2': {'A': 2, 'B': 5, 'C': 8},
'row3': {'A': 3, 'B': 6, 'C': 9}
}
df = pd.DataFrame.from_dict(data, orient='index')
print(df)
输出:
A B C
row1 1 4 7
row2 2 5 8
row3 3 6 9
在这个例子中,我们使用了 pd.DataFrame.from_dict()
函数,并且指定了 orient='index'
,这意味着字典的键(例如 'row1'
, 'row2'
)将成为 DataFrame 的行索引。
示例 3:字典嵌套列表(每个字典中有不同长度的列表)
如果你的字典嵌套的是不规则的列表(即字典的每个键对应不同长度的列表),pandas
会自动处理缺失值(用 NaN
填充缺失的数据)。
data = {
'A': [1, 2, 3],
'B': [4, 5],
'C': [7, 8, 9]
}
df = pd.DataFrame.from_dict(data, orient='index').transpose()
print(df)
输出:
A B C
0 1.0 4.0 7
1 2.0 5.0 8
2 3.0 NaN 9
在这个例子中,列 'B'
少了一个元素,因此缺失的地方会被自动填充为 NaN
。
示例 4:字典嵌套列表,包含嵌套结构
如果字典值本身包含嵌套结构(如列表中的字典),你可以通过一些额外的处理将嵌套数据展平,然后转换为 DataFrame。
假设你的数据如下:
data = {
'ID': [1, 2],
'Details': [
{'name': 'Alice', 'age': 25},
{'name': 'Bob', 'age': 30}
]
}
如果你希望将嵌套的字典展开并放入 DataFrame 中,可以先处理嵌套字典:
# 将 'Details' 列展开
df = pd.json_normalize(data, 'Details', ['ID'])
print(df)
输出:
name age ID
0 Alice 25 1
1 Bob 30 2
这里使用了 pd.json_normalize()
来展开 Details
列中的嵌套字典。
总结
pd.DataFrame()
或 pd.DataFrame.from_dict()
。pd.json_normalize()
来展开字典。pandas
会自动使用 NaN
填充缺失的数据。根据你的数据结构的复杂程度,你可以选择不同的方式来处理和转换为 DataFrame。
九、Dataframe中at、loc、iloc的区别
在Pandas中,at
、loc
和 iloc
是用于访问和操作 DataFrame 中数据的方法,它们有不同的应用场景和行为。以下是它们的主要区别:
1. at
:
at
是用于访问单个元素,通常用于基于行标签和列标签的快速访问。loc
和 iloc
,at
在访问单个元素时会更快,因为它专门优化了这个操作。df.at[row_label, column_label]
示例:
import pandas as pd
df = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6]
})
value = df.at[1, 'B'] # 访问第2行、第B列的值,结果是5
2. loc
:
loc
是基于标签(即行和列的名称)进行访问的。它可以用于选择行、列或行列的子集,支持切片。df.loc[row_labels, column_labels]
,其中 row_labels
和 column_labels
可以是标签列表、单个标签或者切片。loc
允许选择多个行和列,可以传递标签范围进行切片。示例:
value = df.loc[1, 'B'] # 访问第2行、第B列的值,结果是5
subset = df.loc[0:2, ['A']] # 获取第0到第2行和列'A'的子集
3. iloc
:
iloc
是基于整数位置(即行和列的索引位置)进行访问的。它类似于 Python 中的列表索引,用整数来选择行和列。loc
相似,但是使用位置索引而非标签索引。df.iloc[row_positions, column_positions]
,其中 row_positions
和 column_positions
是行列的整数位置,可以是单个位置、列表、或切片。iloc
不支持标签索引。示例:
value = df.iloc[1, 1] # 访问第2行、第2列的值,结果是5
subset = df.iloc[0:2, [0]] # 获取第0到第1行和第0列的子集
总结:
方法 | 基于 | 用法例子 | 描述 |
---|---|---|---|
at |
标签 | df.at[1, 'B'] |
访问单个元素,基于行标签和列标签,速度较快 |
loc |
标签 | df.loc[1, 'B'] |
基于行列标签选择数据,可以切片、选择多个行列的子集 |
iloc |
整数位置 | df.iloc[1, 1] |
基于整数位置选择数据,支持切片和位置索引选择多个行列 |
选择时的考虑:
at
会更高效。loc
。iloc
。
作者:whale fall