我正在尝试创建一个python程序,它提供了两个具有多个工作表的大excel文件之间的差异。我让它把结果打印到excel中,但显然当其中一个单元格包含日期时间数据时,将布尔数据帧与包含日期的数据帧相乘的操作不再有效。我得到以下错误:
TypeError:不支持*:“bool”和“的操作数类型”日期时间。日期时间'
“EDIT”:我刚刚意识到这个方法也不适用于字符串(它只适用于纯数值数据)。对于字符串、数字和时间数据,有什么更好的方法呢?在
#start of program
import pandas as pd
from pandas import ExcelWriter
import numpy as np
df1 = pd.read_excel('4_Input EfE_2030.xlsm',None)
df2 = pd.read_excel('5_Input EfE_2030.xlsm',None)
keys1=df1.keys()
keys2=df2.keys()
writer = ExcelWriter('test1.xlsx')
#loop for all sheets and create new dataframes with the differences
for x in keys1:
df3 = pd.read_excel('4_Input EfE_2030.xlsm',sheetname=x,header=None)
df4 = pd.read_excel('5_Input EfE_2030.xlsm',sheetname=x,header=None)
dif = df3 != df4
df=dif*df3
df2=dif*df4
nrcolumns=len(df.columns)
#when there are no differences in the entire sheet the dataframe will be empty. Add 1 to row indexes so the number coincides with excel rownumbers
if not df.empty:
# df.columns = ['A']
df.index = np.arange(1, len(df) + 1)
if not df2.empty:
# df2.columns = ['A']
df2.index = np.arange(1, len(df) + 1)
#delete rows with all 0
df = df.loc[~(df == 0).all(axis=1)]
df2 = df2.loc[~(df2 == 0).all(axis=1)]
#create new df with the data of the 2 sheets
result = pd.concat([df,df2],axis=1)
print(result)
result.to_excel(writer,sheet_name=x)
更新的答案
方法
这是一个有趣的问题。另一种方法是使用Pandas提供的
Panel
数据结构,将一个Excel工作表中的列值与另一个Excel工作表中的列值进行比较。此数据结构将数据存储为三维数组。通过存储在Panel
中的两个Excel工作表中的数据,我们可以比较由一个或多个列(例如,一个唯一的ID)唯一标识的工作表中的行。通过应用自定义函数将一个工作表中每个列的每个单元格中的值与第二个工作表中同一列的同一单元格中的值进行比较。这种方法的一个好处是每个值的数据类型不再重要,因为我们只是比较值(例如,1 == 1
,'my name' == 'my name'
,等等)。在假设
这种方法对您的数据进行了若干假设:
(我可能没有注意到其他假设。)
实施
这种方法的实现有点复杂。另外,因为我没有访问您的数据的权限,所以我无法针对您的数据定制具体的实现。说到这里,我将使用下面显示的一些虚拟数据来实现这个方法。在
“旧”数据集:
“新”数据集:
^{pr2}$请注意这两个数据帧的以下差异:
col_str
与{col_num
与id
3的行不同col_datetime
与id
3的行不同id
2的行存在于“old”中,而不是“new”中id
4的行存在于“new”中,而不是“old”中好吧,我们开始吧。在第一个数据帧中,我们将读取数据集:
^{3}$然后我们在每个数据帧中添加一个新的版本列,以保持我们的思路清晰。我们稍后还将使用此列将“旧”和“新”数据帧中的行分离到各自独立的数据帧中:
然后我们将“旧”和“新”数据集连接到单个数据帧中。请注意,
ignore_index
参数设置为True
,因此我们忽略了索引,因为它对该操作没有意义:df_full = pd.concat([df_old, df_new], ignore_index=True)
现在我们要标识两个数据帧之间存在的所有重复行。这些行中的所有列值在“旧”和“新”数据帧中都相同。换句话说,这些行不存在差异:
一旦确定,我们就删除这些重复的行。我们剩下的是(a)两个数据帧之间不同的行,(b)存在于“旧”数据帧中而不是“新”数据帧中,(c)存在于“新”数据帧中而不是“旧”数据帧中:
df_diff = df_full.drop_duplicates(subset=['id', 'col_num', 'col_str', 'col_datetime'])
接下来,我们识别并提取
id
(即“旧”和“新”数据帧之间的主键)的值,这些值分别存在于“旧”和“新”数据帧中。需要注意的是,这些id
s不包含存在于一个或其他数据帧中的行,但不包括这两个数据帧中的行(即,删除的行或添加的行):diff_ids = df_diff.set_index('id').index.get_duplicates()
现在我们将
df_full
仅限于diff_ids
中由id
标识的行:df_diff_ids = df_full[df_full['id'].isin(diff_ids)]
现在,我们将“旧”和“新”数据帧中的重复行移动到单独的数据帧中,我们可以插入
Panel
数据结构进行比较:接下来,我们将这两个数据帧的索引都设置为主键(即
id
)。这是Panel
有效工作所必需的:我们把这两个都开槽将数据帧放入
Panel
数据结构中:df_panel = pd.Panel(dict(df1=df_diff_old, df2=df_diff_new))
最后,我们使用自定义函数(
find_diff
)和apply
方法进行比较:如果打印出
^{8}$df_diff
的内容,您可以很容易地注意到在“旧”和“新”数据帧之间发生了哪些值的更改:改进
我会给你留下一些改进的地方。在
原始答案
问题:
问题是您不能对
datetimes
执行算术运算。在但是,您可以对
timedeltas
执行算术运算。在我可以想出一些可能对您有帮助的解决方案:
解决方案1:
将您的
datetimes
转换为字符串。如果我正确地理解了你的问题,你在比较Excel工作表中的差异,对吗?如果是这样,那么我认为
datetimes
是否表示为显式datetimes
(即,您没有执行任何datetime
计算)也不重要。在要实现此解决方案,您需要将
pd.read_excel()' calls and explicitly set the
数据类型parameter to convert your
日期时间修改为字符串:解决方案2:
将您的
datetimes
转换为timedeltas
。对于每个
datetime
列,可以使用:pd.Timedelta(df['LABEL FOR DATETIME COL'])
总的来说,在没有看到您的数据的情况下,我认为解决方案1是最直接的。在
相关问题 更多 >
编程相关推荐