将不同类型的 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 数据框中,拆分列,解析日期的主要内容,如果未能解决你的问题,请参考以下文章

Pandas:将csv文件作为列表加载

使用不同格式(csv、json、avro)将数据加载到 pd.DataFrame 的最快方法

python 将数据CSV加载到Pandas中

将 CSV 加载到 Pandas MultiIndex DataFrame

使用 pyodbc 和 pandas 将 CSV 加载到 .mdb

如何自动将csv转换为pandas?