组合文件时Pandas设置数据类型

时间:2018-01-08 06:08:44

标签: python pandas

我使用下面的代码来组合一堆csv文件。 [UPC]列以000000开头。 Pandas将UPC检测为数值,因此忽略所有前导零。

import pandas as pd
file_ptn = os.path.join('nielsen_sku_fact*.csv')
files = glob.glob(file_ptn)
sch_inx = [
        '[All Markets]',
        '[All Periods]',
        '[UPC]'
        ]
df = reduce(lambda  left,right: pd.DataFrame.combine_first(left,right), [pd.read_csv(f,index_col=sch_inx) for f in files])

挑战在于[UPC]需要设置为索引才能将所有文件合并到同一个模式中。我更喜欢使用combine_first方法来实现代码优雅;所以除了combine_first之外,不需要建议不同的合并/组合方法。

4 个答案:

答案 0 :(得分:3)

我认为您需要更改combine_first并将参数dtype添加到read_csv字典 - 列名称str

同样,对于列名称和sch_inx之间的交集,使用索引numpy.intersect1d并选择相交的列:

dfs = []
di = {d:str for d in sch_inx}
for fp in files:
    df = pd.read_csv(fp, dtype=di)
    #if want only first intersectioned column add [0]
    #col = np.intersect1d(df.columns, sch_inx)[0]
    col = np.intersect1d(df.columns, sch_inx)
    dfs.append(df.set_index(col))

df = reduce(lambda left,right: left.combine_first(right), dfs)

您不能将dtypeindex_col放在pandas 0.22.0中,因为bug

答案 1 :(得分:3)

问题可能在于index_col参数,为什么不在读取csv后设置索引。即

li = [pd.read_csv(f, dtype={d:object for d in sch_inx }).set_index(sch_inx)  for f in files] 

main_df = reduce(lambda  left,right: pd.DataFrame.combine_first(left,right),li)

让我们举一个保留前导零的例子,即

    amount  donorID  recipientID  year
0     0100      101           11  2014
1     0200      101           11  2014
2     0500      101           21  2014
3     0200      102           21  2014
# Copy the above dataframe 

sch_ind = ['amount','donorID']
df = pd.read_clipboard(dtype={d:object for d in sch_ind}).set_index(sch_ind)

print(df)
                recipientID  year
amount donorID                   
0100   101               11  2014
0200   101               11  2014
0500   101               21  2014
0200   102               21  2014

如果它适用于clipboard,则它也适用于csv

答案 2 :(得分:2)

第1点
有几种方法可以保留'[UPC]'列的字符串。

  1. 使用其他帖子中提到的dtype
  2. 使用converters
  3. 之后使用pd.Series.str.zfill
  4. 执行转换

    <强>设置
    让我们从设置一些文件开始。我正在使用Jupyter Notebook,我可以使用方便的%%writefile魔法。

    %%writefile nielson_sku_fact01.csv
    [All Markets],[All Periods],[UPC],A,B
    1,2,0001,3,4
    1,3,2000,7,8
    
    %%writefile nielson_sku_fact02.csv
    [All Markets],[All Periods],[UPC],C,D
    1,4,0001,3,4
    1,3,3000,7,8
    
    %%writefile nielson_sku_fact03.csv
    [All Markets],[All Periods],[UPC],B,D
    1,4,0002,10,11
    1,2,2000,8,8
    

    让我们使用OP代码获取一些变量

    import glob
    import os
    import pandas as pd
    from functools import reduce
    
    files = glob.glob('nielson_sku_fact*.csv')
    sch_inx = [
        '[All Markets]',
        '[All Periods]',
        '[UPC]'
    ]
    

    现在让我们展示三种转换的工作原理:

    1. pd.read_csv('nielson_sku_fact01.csv', dtype={'[UPC]': str})

         [All Markets]  [All Periods] [UPC]  A  B
      0              1              2  0001  3  4
      1              1              3  2000  7  8
      
    2. pd.read_csv('nielson_sku_fact01.csv', converters={'[UPC]': str})

         [All Markets]  [All Periods] [UPC]  A  B
      0              1              2  0001  3  4
      1              1              3  2000  7  8
      
    3. 使用pd.Series.str.zfill

      pd.read_csv('nielson_sku_fact01.csv')['[UPC]'].astype(str).pipe(
          lambda s: s.str.zfill(s.str.len().max()))
      
         [All Markets]  [All Periods] [UPC]  A  B
      0              1              2  0001  3  4
      1              1              3  2000  7  8
      
    4. 第2点
      如果你想要优雅,当pd.DataFrame.combine_first已经是一个带有两个参数的函数时,不需要使用带有两个参数的lambda。此外,您可以将map与准备好的阅读功能结合使用,使其更加干净整洁:

      def read(filename):
          return pd.read_csv(
              filename,
              converters={'[UPC]': str}
          ).set_index(sch_inx)
      
      reduce(pd.DataFrame.combine_first, map(read, files))
      
                                           A     B    C     D
      [All Markets] [All Periods] [UPC]                      
      1             2             0001   3.0   4.0  NaN   NaN
                                  2000   NaN   8.0  NaN   8.0
                    3             2000   7.0   8.0  NaN   NaN
                                  3000   NaN   NaN  7.0   8.0
                    4             0001   NaN   NaN  3.0   4.0
                                  0002   NaN  10.0  NaN  11.0
      

      第3点
      我认为您应该重新考虑使用pd.DataFrame.combine_first,因为glob的性质看起来不像您可以非常轻松地控制文件的顺序。并且您可能会得到不可预测的结果,具体取决于glob如何返回这些文件。除非你不在乎,否则......祝你好运。

答案 3 :(得分:0)

使用read_csv时,可以通过传递dtype参数来设置列的类型。例如:

pd.read_csv(f, index_col=sch_inx, dtype={'[UPC]': 'str'})

请参阅:docs