将不同类型的 CSV 字符串加载到 Pandas 数据框中,拆分列,解析日期
Posted
技术标签:
【中文标题】将不同类型的 CSV 字符串加载到 Pandas 数据框中,拆分列,解析日期【英文标题】:Load CSV Strings With Different Types into Pandas Dataframe, Split Columns, Parse Date 【发布时间】:2017-01-21 07:57:45 【问题描述】:我有两个关于大型 csv 文件的问题,该文件包含以下格式的字符串格式的数据:
"XAU=,XAU=,XAG=,XAG="
"25/08/2014 6:00:05,1200.343,25/08/2014 6:00:03,19.44,"
"25/08/2014 6:00:05,1200,,,"
有没有办法有效地将其加载到 pandas 数据框对象中?或者,多个 pandas Series 对象也可以完成这项工作。到目前为止,我尝试过:
df = read_csv(path, header=None)
df[0].str[0:-1].str.split(',', return_type='frame')
第二行是来自此线程pandas split string into columns 的答案。但是,我想知道是否有更好的方法,特别是因为我有不同的数据类型?其次,如何正确解析to_datetime()
的日期。我试图重新索引df
并使用df.index = df.index.to_datetime()
。这只奏效了一半,因为它没有严格保持dd/mm/yyyy ...
格式。某些日期被错误地解析为mm/dd/yyyy ...
。我正在寻找快速的方法,因为最终我会遍历许多这样的 csv。感谢您的帮助!
编辑:理想情况下,这种形式的数据也应该被处理:
"XAU=,XAU=,XAG=,XAG="
"25/08/2014 6:00:05,1200.343,25/08/2014 6:00:03,19.44,"
",,25/08/2014 6:00:05,19.50,"
所以有了下面提供的答案,
data = StringIO(
'''
"XAU=,XAU=,XAG=,XAG="
"25/08/2014 6:00:05,1200.343,25/08/2014 6:00:03,19.44,"
",,25/08/2014 6:00:05,19.5,"
''')
df 会变成:
XAU XAU XAG XAG
0 25/08/2014 6:00:05 1200.343 25/08/2014 6:00:03 19.44
1 , 25/08/2014 6:00:05 19.5 \n
【问题讨论】:
【参考方案1】:您可以对read_csv
中的所有内容进行预处理,如图所示:
import csv
data = StringIO(
'''
"XAU=,XAU=,XAG=,XAG="
"25/08/2014 6:00:05,1200.343,25/08/2014 6:00:03,19.44,"
"25/08/2014 6:00:05,1200,,,"
''')
df = pd.read_csv(data, quoting=csv.QUOTE_NONE, index_col=False, escapechar='"', \
parse_dates=[0, 2]).rename(columns=lambda x: x.split("=")[0])
df
df.dtypes
XAU datetime64[ns]
XAU float64
XAG datetime64[ns]
XAG float64
dtype: object
分手:
quoting=csv.QUOTE_NONE:指示编写器对象从不引用字段
index_col=False:不要使用第一列作为索引
escapechar=": 用于转义分隔符的字符串
parse_dates=[0, 2]:将列(0,2 → order)转换为datetime
对象
要读取列的子集,您可以在 usecols
的帮助下提供适当的整数索引,如下所示:
df = pd.read_csv(data, quoting=csv.QUOTE_NONE, index_col=False, escapechar='"', \
parse_dates=[0], usecols=[0,1]).rename(columns=lambda x: x.split("=")[0])
df
如果要将XAU
的两列转换成一个系列对象:
df.columns = df.columns + [str('_%d'%(i)) for i in list(range(len(df.columns)))]
ser = pd.Series(data=df['XAU_1'].values, index=df['XAU_0'].values, name='XAU')
ser
2014-08-25 06:00:05 1200.343
2014-08-25 06:00:05 1200.000
Name: XAU, dtype: float64
type(ser)
pandas.core.series.Series
较新案例失败的原因是escapechar
跳过了第一个分隔符,导致未正确捕获空字符串。
如果是这种情况,您最好完全忽略 escapechar
并继续如下所示:
对于新旧数据的结合:
data = StringIO(
'''
"XAU=,XAU=,XAG=,XAG="
"25/08/2014 6:00:05,1200.343,25/08/2014 6:00:03,19.44,"
"25/08/2014 6:00:05,1200,,,"
",,25/08/2014 6:00:05,19.50,"
''')
df = pd.read_csv(data, quoting=csv.QUOTE_NONE, index_col=False, na_values=[""],
parse_dates=[2]).rename(columns=lambda x: x.strip('"').split("=")[0])
old_cols = df.columns
# Index(['XAU', 'XAU', 'XAG', 'XAG'], dtype='object')
new_cols = [col[0] for col in list(enumerate(df.columns))]
# [0, 1, 2, 3]
df.columns = new_cols
# Converting first column to datetime dtype
df[0] = pd.to_datetime(df[0].str.replace('"', ''))
df.columns = old_cols
df
df.dtypes
XAU datetime64[ns]
XAU float64
XAG datetime64[ns]
XAG float64
dtype: object
【讨论】:
只是好奇,是否可以只读取数据框中的两个“XAU”列或直接读取熊猫系列对象中的两个“XAU”列? 是的,可以选择有限数量的列读入数据框(查看编辑后的回复)。 不幸的是我遇到了一个微妙的问题。当数据以以下形式到达时(略有不同):''' "XAU=,XAU=,XAG=,XAG=" "25/08/2014 6:00:05,1200.343,25/08/2014 6 :00:03,19.44," ",,25/08/2014 6:00:05,19.50," ''' df 将包含一个分号作为第二行和第一列的值。结果,数据将无法正确对齐。 因此,日期解析也失败了。 太好了,非常感谢。它现在工作正常。仅作为最后一句话,我想知道是否也可以通过列索引指定价格报价的 dtype,这样熊猫确实需要推断它?一般来说,从这种“类似字符串”的格式中读取数据是否明智(这就是提供给我的方式)?以上是关于将不同类型的 CSV 字符串加载到 Pandas 数据框中,拆分列,解析日期的主要内容,如果未能解决你的问题,请参考以下文章
使用不同格式(csv、json、avro)将数据加载到 pd.DataFrame 的最快方法
将 CSV 加载到 Pandas MultiIndex DataFrame