目录
(1)TypeError: read_csv() got an unexpected keyword argument 'mangle_dupe_cols'
(2)使用ExcelWriter对象来在同一个Excel文件的不同Sheet中写入多个DataFrame。
遇到的问题
(1)TypeError: read_csv() got an unexpected keyword argument 'mangle_dupe_cols'
解决:https://github.com/huggingface/datasets/pull/5745
版本问题: 正解! pip install pandas==1.5.3
1.1 文件读取
(1) names和header
names
和header
参数在pandas的read_excel
函数中都是用来处理列名称的。
names
参数允许你为加载的数据框指定列名。这是一个字符串列表,长度应该等于数据框的列数。例如 names=['col1', 'col2', 'col3']
。当你使用这个参数时,无论原始数据的列标题是什么,都会被替换成你指定的列名。
header
参数则是用来指定原始数据中哪一行作为列名。默认值是0,表示第一行是列名。如果你的数据没有列名,或者你不想使用原始数据的列名,你可以设置 header=None
。
所以,这两个参数的区别在于,names
是直接指定列名,而 header
是从原始数据中选择列名。
例如:
# 使用原始数据的第二行作为列名
pd.read_excel(read_path, header=1)
# 忽略原始数据的列名,指定新的列名
pd.read_excel(read_path, header=None, names=['col1', 'col2', 'col3'])
(2) usecols 用于指定取值列
# 只取表格中的‘问题’列,其他列不会取到
df_new = pd.read_excel(read_path, sheet_name='new', usecols=['问题'])
(3) 全表读取
import pandas as pd
# 读取Excel文件
xls = pd.read_excel('filename.xlsx', sheet_name=None)
# xls现在是一个包含所有sheets的字典,键为sheet名,值为对应的DataFrame
for sheet_name, df in xls.items():
print(f"Processing sheet: {sheet_name}")
# 在这里你可以对df进行处理
...
1.2 文件保存
(1)常用方法
这种写法逻辑--先删后写:往同一个excel中插入数据时,即使不同的sheet名,也会默认先把之前已存在的sheet先删掉再写入新数据。
import pandas as pd
df1 = pd.DataFrame({
'A': ['foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'foo'],
'B': ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'],
'C': [1, 2, 3, 4, 5, 6, 7, 8]
})
df2 = pd.DataFrame({
'D': ['apple', 'banana', 'cherry', 'durian'],
'E': ['red', 'yellow', 'red', 'green'],
'F': [1, 2, 3, 4]
})
# 使用pd.DataFrame()函数将其转换为DataFrame
df = pd.DataFrame(datas1, columns=['request_id', 'question', 'answer', 'create_time', 'answer_is_gpt'])
# 数据写入excel
df.to_excel(out_path, sheet_name='问答', index=False)
(2)使用ExcelWriter对象来在同一个Excel文件的不同Sheet中写入多个DataFrame。
import pandas as pd
df1 = pd.DataFrame({
'A': ['foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'foo'],
'B': ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'],
'C': [1, 2, 3, 4, 5, 6, 7, 8]
})
df2 = pd.DataFrame({
'D': ['apple', 'banana', 'cherry', 'durian'],
'E': ['red', 'yellow', 'red', 'green'],
'F': [1, 2, 3, 4]
})
# 创建一个ExcelWriter对象
with pd.ExcelWriter('output.xlsx') as writer:
df1.to_excel(writer, sheet_name='Sheet1', index=False)
df2.to_excel(writer, sheet_name='Sheet2', index=False)
# 在上面的代码中,我们首先创建了两个DataFrame df1 和 df2。然后,我们创建了一个ExcelWriter对象,并将这两个DataFrame分别写入到’output.xlsx’文件的’Sheet1’和’Sheet2’中。注意,我们使用了Python的with语句来自动关闭ExcelWriter,这是一个好的做法,可以确保所有的数据都被正确地写入文件。
1.3 pandas拼接
(1)常用方法:pd.concat
pd.concat是pandas库中的一个函数,用于将两个或多个pandas对象(如Series,DataFrame)沿特定轴连接。此外,pd.concat还有很多其他参数,如join(设置连接方式,如’inner’,‘outer’),keys(创建分层索引)等,可以根据具体需求进行设置。具体见以下案例。
注意,拼接的时候不管axis=0还是1,都是按行索引index一一对应拼接,比如:
import pandas as pd
import numpy as np
df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
'B': ['B0', 'B1', 'B2'],
'C': ['C0', 'C1', 'C2']})
################################# 1、不同行index的拼接【正确演示】
df1= df1.iloc[1:2, :-1]
print("df1: \n", df1)
# df1:
# A B
# 1 A1 B1
# 重置行索引
df1.reset_index(drop=True, inplace=True)
print("df1: \n", df1)
# df1:
# A B
# 0 A1 B1
df2 = pd.DataFrame(np.array([[''] * 3]), columns=['B1', 'C', 'D'])
print('df2 : \n', df2 )
# df2 :
# B1 C D
# 0
df = pd.concat([df1, df2 ], axis=1)
print(df)
# A B B1 C D
# 0 A1 B1 NaN NaN NaN
可以看到df1的行索引最开始是1,经重置后改为0;df2也是0。按预期输出拼接后的结果。
################################# 2、不同行index的拼接【错误演示】
df1= df1.iloc[1:2, :-1]
print("df1: \n", df1)
# df1:
# A B
# 1 A1 B1
df2 = pd.DataFrame(np.array([[''] * 3]), columns=['B1', 'C', 'D'])
print('df2 : \n', df2 )
# data_frame:
# B1 C D
# 0
df = pd.concat([df1, df2 ], axis=1)
print(df)
# A B B1 C D
# 1 A1 B1 NaN NaN NaN
# 0 NaN NaN
可以看到df1的行索引是1,df2则是0,拼接后的结果是0,1各一行
a、列名无重复
import pandas as pd
# 案例1:创建两个DataFrame
df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']},
index=[0, 1, 2, 3])
df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'],
'B': ['B4', 'B5', 'B6', 'B7'],
'C': ['C4', 'C5', 'C6', 'C7'],
'D': ['D4', 'D5', 'D6', 'D7']},
index=[4, 5, 6, 7])
# 沿着行轴(axis=0)连接这两个DataFrame
result = pd.concat([df1, df2])
print(result)
# 在这个例子中,pd.concat将df1和df2沿着行轴(即垂直方向)连接了起来,因为默认的axis参数值是0。
# 你也可以通过设置axis参数为1来沿列轴(即水平方向)连接DataFrame:
result = pd.concat([df1, df2], axis=1)
# 案例2:给空df拼接数据
df_new = pd.DataFrame()
# 创建一个1行3列的数据
df_tmp = pd.DataFrame(np.array([['aa', 'bb', 'cc']]))
# 加入新的数据表
df_new = pd.concat([df_new, df_tmp], axis=0)
b、列名有重复
1)df1、df2有交叉重复列
df1和df2都有a、b列,但可以正常拼接。
2)df3有重复列,无法和其他df拼接
因为df3的列索引abcab中ab列重复,所以导致df3无法与df1进行concat堆叠。这种就需要用到“1.5中列索引的修改”
3)df3、df4各自有重复列,但两者列名一模一样
df3和df4可以正常拼接,这是因为:虽然df3,df4的列索引abcab中ab列重复,但是df3,df4的列索引相同,所以concat也能正常运行,这就是例外情况。
(2)concat方法的join参数
join参数在pandas.concat函数中用于指定连接的方式。有两个选项,‘inner’和’outer’。
‘outer’:这是默认的连接方式,它会返回所有的行,并且会用NaN来填充那些在某些数据中不存在的列的值。
‘inner’:这种方式只会返回那些在所有数据中都有的行,并且只包含那些在所有数据中都存在的列。
import pandas as pd
df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
'B': ['B0', 'B1', 'B2'],
'C': ['C0', 'C1', 'C2']},
index=[1, 2, 3])
df2 = pd.DataFrame({'B': ['B2', 'B3', 'B4'],
'C': ['C2', 'C3', 'C4'],
'D': ['D2', 'D3', 'D4']},
index=[2, 3, 4])
############方案1:外连接
result_outer = pd.concat([df1, df2], join='outer')
print(result_outer)
##输出(注意NaN值):
A B C D
1 A0 B0 C0 NaN
2 A1 B1 C1 NaN
3 A2 B2 C2 NaN
2 NaN B2 C2 D2
3 NaN B3 C3 D3
4 NaN B4 C4 D4
############ 方案2:内连接
result_inner = pd.concat([df1, df2], join='inner')
print(result_inner)
## 输出(只包含共同的列和行):
B C
1 B0 C0
2 B1 C1
3 B2 C2
2 B2 C2
3 B3 C3
4 B4 C4
1.4 df的value获取和转换
(1)value获取
- 如果你想获取整个DataFrame或者某一列的值,可以使用以下代码:
values = df['column_name']
- 要获取某一列 不重复的 非空值(非None 或 nan)
unique_values = df['column_name'].dropna().unique()
- 要获取整个DataFrame的值,可以使用
.values
属性:
values = df['column_name'].values
这将返回一个NumPy数组,其中包含DataFrame中的所有值。
(2)value类型转换:
numpy_array、list、tuple、dict
- numpy_array
df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
'B': ['B0', 'B1', 'B2'],
'C': ['C0', 'C1', 'C2']})
# 1、获取values,结果是numpy.array类型
datas_array = df1.values
print(datas_array)
# [['A0' 'B0' 'C0']
# ['A1' 'B1' 'C1']
# ['A2' 'B2' 'C2']]
- list
# 2、转list类型
data_list = df1.values.tolist()
print(data_list )
# [['A0', 'B0', 'C0'], ['A1', 'B1', 'C1'], ['A2', 'B2', 'C2']]
- tuple
# 3、转tuple类型
# 方案一:
tuples = [tuple(x) for x in df1.values]
print(tuples)
# [('A0', 'B0', 'C0'), ('A1', 'B1', 'C1'), ('A2', 'B2', 'C2')]
# 方案二:
# 将DataFrame的值转换为元组
for row in df1.itertuples(index=False):
print(row)
# Pandas(A='A0', B='B0', C='C0')
# Pandas(A='A1', B='B1', C='C1')
# Pandas(A='A2', B='B2', C='C2')
- dict
xx_df.to_dict(orient="records")这个函数调用做的事情是将xx_df DataFrame的每一行转换为一个字典,然后将这些字典放在一个列表中。
orient="records"参数指定了字典的键应该是DataFrame的列名,每个键的值应该是该列在特定行中的值。
import pandas as pd
data = {'Name': ['John', 'Anna'], 'Age': [28, 23]}
df = pd.DataFrame(data)
print(df)
输出:
Name Age
0 John 28
1 Anna 23
执行to_dict(orient="records")将它转换为字典列表:
print(df.to_dict(orient='records'))
输出:[{'Name': 'John', 'Age': 28}, {'Name': 'Anna', 'Age': 23}]
每个字典代表DataFrame的一行,字典的键是列名,值是该行在该列的值。
1.5 索引的修改
(1)行索引
使用DataFrame的reset_index()方法重置行索引。如果你想要重置行索引为默认值(即从0开始的整数),你可以通过reset_index()和drop=True参数来实现:
import pandas as pd
# 创建一个DataFrame
df = pd.DataFrame({
'A': ['foo', 'bar', 'baz'],
'B': ['one', 'two', 'three'],
'C': [1, 2, 3]
}, index=['x', 'y', 'z'])
print("Before reset index:")
print(df)
# 重置索引
df_reset = df.reset_index(drop=True)
print("After reset index:")
print(df_reset)
以上例子中,我们首先创建了一个索引为’x’, ‘y’, 'z’的DataFrame。然后,我们使用reset_index(drop=True)方法重置索引。drop=True参数表示我们不希望保留原来的索引。如果你希望在重置索引的同时保留原来的索引,你可以省略这个参数。
请注意,reset_index()方法不会在原地修改DataFrame,而是返回一个新的DataFrame。如果你想要在原地修改DataFrame,你可以添加inplace=True参数:
df.reset_index(drop=True, inplace=True)
(2)列索引
方案一:rename
df.rename(columns=columns, inplace=True)这个命令的作用是重命名DataFrame的列名。columns参数应该是一个字典,其中键是旧的列名,值是新的列名。
df = pd.DataFrame({
'A': ['A0', 'A1', 'A2'],
'B': ['B0', 'B1', 'B2']
})
df.rename(columns={'A': 'a', 'B': 'b'}, inplace=True)
在这个例子中,df.rename(columns={'A': 'a', 'B': 'b'}, inplace=True)将列名’A’改为’a’,列名’B’改为’b’。
方案二:遍历并重命名
如果DataFrame中有重复的列名,你可以通过遍历列名并添加后缀的方式进行重命名。
import pandas as pd
# 创建一个有重复列名的DataFrame
df = pd.DataFrame([[1, 2, 3, 4], [5, 6, 7, 8]], columns=['A', 'B', 'A', 'B'])
# 创建一个空字典,用于存储新的列名
new_columns = {}
for col in df.columns:
if col not in new_columns:
new_columns[col] = col
else:
i = 1
while f"{col}_{i}" in new_columns:
i += 1
new_columns[f"{col}_{i}"] = col
# 重命名列名
df.rename(columns=new_columns, inplace=True)
print(df)
1.6 切片
(1)iloc 和 loc
a、相同点
使用df.iloc[]或df.loc[]提取单行数据时,返回的是一个Series对象。
而当提取多行数据时,返回的是一个DataFrame对象。
举例来说:
import pandas as pd
df = pd.DataFrame({
'A': ['A0', 'A1', 'A2'],
'B': ['B0', 'B1', 'B2']
})
print(type(df.iloc[0])) # <class 'pandas.core.series.Series'>
print(type(df.iloc[0:2])) # <class 'pandas.core.frame.DataFrame'>
在这个例子中,当我们提取第一行数据(df.iloc[0])时,返回的是一个Series对象。而当我们提取第一行和第二行数据(df.iloc[0:2])时,返回的是一个DataFrame对象。
如果你希望即使只提取一行数据,也返回DataFrame对象,你可以使用切片的方式,如df.iloc[0:1],这样即使只提取一行数据,也会返回DataFrame对象。
注意:Series对象在拼接时会报错,所以切片最好指定start和end。
b、不同点
.loc[]
需要你提供行标签和列标签(也就是行和列的名称):
df.loc[row_label, 'column_name'] = new_value
.iloc[]
需要你提供行索引和列索引(也就是行和列的位置):
df.iloc[row_index, column_index] = new_value
其中 new_value
是你想要赋给这个单元格的新值。
如果你想给整个列赋值,你可以直接使用列的名称:
df['column_name'] = new_value
这会将 new_value
赋值给 column_name
这一列的所有单元格。如果 new_value
是一个列表或数组,那么它的长度必须和 DataFrame 的行数相同。
(2)iat 和 at
a、相同点
都可以获取excel中指定单元格的值。
b、不同点
at
方法用于通过行标签和列标签(即行和列的名称)获取值,如:
value = df.at[0, 'column_name']
iat
方法用于通过行索引和列索引(即行和列的位置)获取值,如:
value = df.iat[0, 0]