从sql中检测python pandas dtypes

时间:2016-09-02 18:50:07

标签: python sql csv pandas dataframe

我对Pandas DataFrame关于Dtype检测的行为感到非常困扰。

我使用' read_sql_query'从数据库中检索数据以构建DataFrame,然后将其转储到csv文件中。

我不需要任何改造。只需将其转储到csv文件中并更改表单中的日期字段:'%d /%m /%Y'

但是:

self.dataframe.to_csv(self.fic,
                   index=False,
                   header=False,
                   sep='|',
                   mode='a',
                   encoding='utf-8',
                   line_terminator='\n',
                   date_format='%d/%m/%Y
                   )

会错过转换/格式化某些日期字段...

我试图用另一种方式做到:

l = list(self.dataframe.select_dtypes(include=['datetime64']).columns)
for i in l:
    self.dataframe[i] = self.dataframe[i].dt.strftime('%d/%m/%Y')

我很满意,但是更多的测试显示出一种奇怪的行为:

如果我的sql请求只选择了两个nuplet:

requete = 'select * from DOMMAGE_INTERET where doi_id in (176433, 181564)'

无论在csv或DataFrame中形成什么,一切都有效。

它正确检测日期字段:

df.dtypes
doi_id                         int64
aff_id                         int64
pdo_id                         int64
doi_date_decision     datetime64[ns]
doi_date_mod          datetime64[ns]
doi_montant                  float64
doi_reste_a_payer             object
doi_appliquer_taux             int64
doi_date_update       datetime64[ns]
afg_id                         int64
dtype: object

但使用其他选择时

requete = 'select * from DOMMAGE_INTERET where rownum < 100'
再次错过了。实际上,字段类型的检测方式不同:

doi_id                         int64
aff_id                         int64
pdo_id                         int64
doi_date_decision             object
doi_date_mod          datetime64[ns]
doi_montant                  float64
doi_reste_a_payer             object
doi_appliquer_taux             int64
doi_date_update       datetime64[ns]
afg_id                         int64
dtype: object

正如您所看到的:&#39; doi_date_decision&#39;类型确实根据请求选择而改变但当然,这是一组相同的数据!!!

难道不奇怪吗?

您对这种行为有解释吗?

3 个答案:

答案 0 :(得分:2)

您的to-csv操作未转换所有指定的日期字段,因为正如您所提到的,并非所有日期时间列都以日期时间格式读入,而是在当前数据框中显示为字符串( object dtype) 。这是从外部源读取的不幸副作用,因为导入的系统 - 包括Python,SAS,Stata,R,Excel等 - 除非另外明确定义,否则尝试通过前几行定义列。

幸运的是,pandas的read_sql_query()维护了parse_dates的参数。因此,请考虑在读取操作期间定义日期,因为此参数采用列表或字典:

df = read_sql_query('select * from DOMMAGE_INTERET where rownum < 100', engine, 
                    parse_dates = ['doi_date_decision', 'doi_date_mod', 'doi_date_update'])

或者,在阅读之前和to_csv之前使用pd.to_datetime()进行转化:

df['doi_date_decision'] = pd.to_datetime(df['doi_date_decision'])

大多数RDMS都以YYYY-MM-DD HH:MM:SS格式维护日期时间,与pandas格式保持一致。

答案 1 :(得分:1)

如果没有一些数据样本,很难深入研究您的问题。但是,您可能会遇到以下两种情况之一:

  • 您在第二种情况下选择的某些行包含NULL值,这会阻止pandas将您的列自动解释为日期时间
  • 您的数据库中有不同的MDY约定,而某些低于13月的日期会被解析为日期,而其他日期则不会被保存为字符串,直到您在DMY中手动转换为止

答案 2 :(得分:0)

感谢Boud和Parfait。他们的答案是正确的:

我的所有测试都显示缺少日期字段会使Dtype检测失败。

read_sql_query()有一个参数来定义具有日期类型的字段。我想要解决这个问题。

可悲的是,从现在开始,我一直在使用完整的通用处理来处理数百个表格。 使用'read_sql_query'参数'parse_dates'意味着先做元数据定义工作(比如描述每个表的json文件)。

实际上,我还发现当列中有NaN字段时,整数会更改为浮点数...

如果我要阅读csv平面文件,我可以理解数据类型很难检测......但是来自数据库(read_sql_query)!熊猫有SqlAlchelmy作为依赖。而SqlAlchemy(甚至任何较低级别的Python数据库驱动程序(cx_Oracle,DB API))都具有检测数据类型的反射机制。 Pandas可能一直在使用这些元数据来保持数据类型的完整性。