我正在使用许多不同的csv文件作为熊猫数据帧读取,然后从中提取有趣的indies和数据,并将其收集到一个新的数据帧中,我逐行构建然后保存。每行表示一个文件中的信息。
原始数据帧按毫秒精度纪元时间编制索引。虽然时代是不必要的精确,但我无法改变任何事情。
>>> df.index
Int64Index([1382441313687, 1382441314687, 1382441315687, 1382441316687,
1382441317687, 1382441318687, 1382441319687, 1382441320687,
1382441321687, 1382441322687,
...
1382445583687, 1382445584687, 1382445585687, 1382445586687,
1382445587687, 1382445588687, 1382445589687, 1382445590687,
1382445591687, 1382445592687],
dtype='int64', name=u'time', length=4280)
我通过构建一个有趣的值列表并从中创建一系列来构建新的数据帧,然后将其追加到数据帧。
columns = ['Start time', 'End time']
summary = pd.DataFrame(columns=columns)
for i, df in enumerate(long_list_of_dfs):
start_time = df.index[0]
end_time = df.index[-1]
data = [start_time, end_time]
new_line = pd.Series({key:val for key, val in zip(columns, data)})
summary = summary.append(new_line)
summary.to_csv(out_dir)
我使用摘要中保存的 indize 来快速索引原始数据帧中的有趣点。但是,在构建新数据帧时,会丢失一些精度,最终得到以下结果:
>>> for line in open(out_dir):
... print(line)
,Start time,End time
0,1.38244131369e+12,138244559269e+12
再次阅读此摘要时,我不能再使用这些值来索引原始数据帧,因为它会导致 KeyError。直接构建数据帧时不会发生这种情况:
>>> summary2 = pd.DataFrame({'Start time':[1382441313687], 'End time':[1382445592687]})
>>> summary2
End time Start time
0 1382445592687 1382441313687
>>> summary2.to_csv(out_dir)
>>> for line in open(out_dir):
... print(line)
,Start time,End time
0,1382441313687,1382445592687
有谁知道为什么会发生这种转换?我知道我可以指定数据类型,但我有很多具有不同数据类型的列,宁愿省去麻烦。我觉得如果这些值保持原始格式也会更直观。
编辑我想强调的是,我在 for 循环中构建数据帧,因为我每行都想添加许多感兴趣的数据点。此外,原始数据帧的数量相当高(~90.000 个文件 @ 每个 20MB),所以我只想打开每个文件一次。
上面的代码只是一个工作示例,表明尽管数据是整数,但最后两位数字被四舍五入,大概在附加行中。new_line
系列的数据仍保留其原始格式,最多为最后两位数字。
下面是前 10 行的 summary.info() 输出。如您所见,有些列包含 NaN,但也有一些不包含。我希望没有 NaN 的列保留其整数格式。
>>> summary.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 88158 entries, 0 to 88157
Data columns (total 46 columns):
Date added 88158 non-null object
Filename 88158 non-null object
ACID 88158 non-null int64
FLID 88158 non-null int64
Flag 88158 non-null object
L ESN 86986 non-null float64
R ESN 86986 non-null float64
Start time 88158 non-null float64
End time 88158 non-null float64
Total duration 88158 non-null float64
EDIT2这是另一个简短的示例,用于显示我在使用长整数逐行构建数据帧时的问题。
>>> df = pd.DataFrame(columns=['a', 'b'])
>>> df.loc[len(df.index)] = [1382441313687, 1382441314687]
>>> df
a b
0 1.382441e+12 1.382441e+12
>>> df.loc[0, 'a']
1382441313687.0 # Correct data!
>>> df.to_csv(out_dir)
>>> for line in open(out_dir):
... print(line)
,a,b
0,1.38244131369e+12,1.38244131469e+12 # Not correct! 1382441313690 != 1382441313687
这是因为你附加了一个Series
,它有一个dtype
,所以如果它包含 1 个float
,其他的也会被投射到float
。
我只能通过稍微调整您的代码来重现您的问题
示例数据生成
columns = ['sample_data']
columns2 = ['Start time', 'End time'] + columns
long_list_of_dfs = [pd.DataFrame(index=[i**2 + j for j in range(i)], columns=columns, data=[j**2 for j in range(i)]) for i in range(5, 15)]
改编的原始代码
summary2 = pd.DataFrame(columns=columns2)
for i, df in enumerate(long_list_of_dfs):
start_time = df.index[0]
end_time = df.index[-1]
data = [df[k].mean() for k in columns]
new_line = pd.Series({key:val for key, val in zip(columns2, [start_time, end_time] + data)}, name=i)
summary2 = summary.append(new_line)
summary2.info()
结果:
<class 'pandas.core.frame.DataFrame'>
Int64Index: 11 entries, 0 to 9
Data columns (total 3 columns):
Start time 11 non-null float64
End time 11 non-null float64
sample_data 11 non-null float64
dtypes: float64(3)
memory usage: 352.0 bytes
new_line
End time 209.0
Start time 196.0
sample_data 58.5
Name: 9, dtype: float64
因此转换发生在追加之前
摘要生成器
防止这种情况的一种方法是 不是为每个原始DataFrame
制作Series
,而是使用这样的生成器。 这可以是您用于生成所需摘要的任何方法
def get_summary_data(long_list_of_dfs, columns):
for df in long_list_of_dfs:
s = [df[k].mean() for k in columns]
# print(df.index[0], df.index[-1], *s)
yield (df.index[0], df.index[-1], *s)
然后连接
summary = pd.DataFrame(data=get_summary_data(long_list_of_dfs, columns), columns=columns2)
结果
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10 entries, 0 to 9
Data columns (total 3 columns):
Start time 10 non-null int64
End time 10 non-null int64
sample_data 10 non-null float64
dtypes: float64(1), int64(2)
memory usage: 320.0 bytes
总结:
Start time End time sample_data
0 25 29 6.000000
1 36 41 9.166667
2 49 55 13.000000
3 64 71 17.500000
4 81 89 22.666667
5 100 109 28.500000
6 121 131 35.000000
7 144 155 42.166667
8 169 181 50.000000
9 196 209 58.500000
可以使用to_csv()
导出此DataFrame
我还没有追踪到你的精度损失发生在哪里,但是
summary = pd.DataFrame([(df.index[0], df.index[-1]) for df in long_list_of_dfs],
columns=['Start Time', 'End Time'])
当我尝试它时,工作没有损失,并且与您的摘要2相匹配。
编辑:刚刚看到主要的帖子编辑。
看起来选择单个值.loc
会将整数转换为浮点数,尽管这似乎不适用于较长的选择。但是,即使这样,如果在一系列此类操作中,np.float64
也会保留在df.to_csv(file), pd.read_csv(file)
操作下。问题似乎出现在混合数据类型给出 Series dtypeobject
上,然后导致这些浮点数在写入文件时被视为它们的字符串表示,从而导致精度损失。
因此,在将每个 df 中所需的值提取到元组之前,避免转换为 pandas 对象,
df_summaries = []
columns = ['Start time', 'End time'] # and any other you wanted here
for df in long_list_of_dfs:
# build your tuples of desired df info
summary = pd.DataFrame(df_summaries, columns=columns)
或者为每个构造一个单行 df,以允许按字段正确识别数据类型,并在这些数据类型上使用pd.concat
(这比为每个数据类型使用.append
要快得多)
df_summaries = []
columns = ['Start time', 'End time'] # and any other you wanted here
for df in long_list_of_dfs:
# build your summary row dataframes of desired info from full-size dataframes
summary = pd.concat(df_summaries)
应该可以解决您的问题。
注意:我无法重现 Edit2 中看到的问题。按照这些步骤对我来说,可以完全精确地恢复浮标。