使用两个分隔符将 CSV 导入 pandas

Posted

技术标签:

【中文标题】使用两个分隔符将 CSV 导入 pandas【英文标题】:Import CSV to pandas with two delimiters 【发布时间】:2017-01-22 03:00:39 【问题描述】:

我有一个带有两个分隔符 (;) 和 (,) 的 CSV,它看起来像这样:

vin;vorgangid;eventkm;D_8_lamsoni_w_time;D_8_lamsoni_w_value
V345578;295234545;13;-1000.0,-980.0;7.9921875,11.984375
V346670;329781064;13;-960.0,-940.0;7.9921875,11.984375

我想将它导入到 pandas 数据框中,使用 (;) 作为列分隔符,(,) 作为 listarray 的分隔符,使用 float 作为数据类型。到目前为止,我正在使用这种方法,但我确信那里有一些更简单的方法。

aa=0;
csv_import=pd.read_csv(folder+FileName, ';')
for col in csv_import.columns:
aa=aa+1
if type(csv_import[col][0])== str and aa>3:
    # string to list of strings
    csv_import[col]=csv_import[col].apply(lambda x:x.split(','))
    # make the list of stings into a list of floats
    csv_import[col]=csv_import[col].apply(lambda x: [float(y) for y in x])

【问题讨论】:

【参考方案1】:

首先使用;作为分隔符读取CSV:

df = pd.read_csv(filename, sep=';')

更新:

In [67]: num_cols = df.columns.difference(['vin','vorgangid','eventkm'])

In [68]: num_cols
Out[68]: Index(['D_8_lamsoni_w_time', 'D_8_lamsoni_w_value'], dtype='object')

In [69]: df[num_cols] = (df[num_cols].apply(lambda x: x.str.split(',', expand=True)
   ....:                                               .stack()
   ....:                                               .astype(float)
   ....:                                               .unstack()
   ....:                                               .values.tolist())
   ....:                )

In [70]: df
Out[70]:
       vin  vorgangid  eventkm D_8_lamsoni_w_time     D_8_lamsoni_w_value
0  V345578  295234545       13  [-1000.0, -980.0]  [7.9921875, 11.984375]
1  V346670  329781064       13   [-960.0, -940.0]  [7.9921875, 11.984375]

In [71]: type(df.loc[0, 'D_8_lamsoni_w_value'][0])
Out[71]: float

旧答案:

现在我们可以将数字拆分为“数字”列中的列表:

In [20]: df[['D_8_lamsoni_w_time',  'D_8_lamsoni_w_value']] = \
    df[['D_8_lamsoni_w_time',  'D_8_lamsoni_w_value']].apply(lambda x: x.str.split(','))
In [21]: df
Out[21]:
       vin  vorgangid  eventkm D_8_lamsoni_w_time     D_8_lamsoni_w_value
0  V345578  295234545       13  [-1000.0, -980.0]  [7.9921875, 11.984375]
1  V346670  329781064       13   [-960.0, -940.0]  [7.9921875, 11.984375]

【讨论】:

感谢您的建议。我有 2 个 cmets:1)如果你有超过 2 个列,我猜第 [20] 行可以打包到一个 for 循环中,但是它与我的方法基本相同,不是吗? 2)我认为最后你仍然会得到一个字符串列表,例如type(df.ix[0,4][0]) == 'str' @valenzio,请检查更新部分 - 我已经完全重写了代码并解决了您的两个问题 谢谢伙计,这看起来好多了,但是如果您在第 67 行和第 68 行有 100 个条目,您仍然需要两个 for 循环,我正在寻找类似于 Ami Tavory 建议的解决方案。基本上是一个具有正确参数的导入命令 @valenzio,不,不需要额外的循环 @MaxU,好好想一想:我提供的数据只是一小部分,以使其更具可读性。实际上,我有 100 多个不同名称的列,因此我需要在 for 循环中创建“num_cols”,并使用一个来为不同的列分配新的数据类型。【参考方案2】:

您可以在read_csv 中使用参数converters 并定义用于拆分的自定义函数:

def f(x):
    return [float(i) for i in x.split(',')]

#after testing replace io.StringIO(temp) to filename
df = pd.read_csv(io.StringIO(temp), 
                 sep=";", 
                 converters='D_8_lamsoni_w_time':f, 'D_8_lamsoni_w_value':f)
print (df)
       vin  vorgangid  eventkm D_8_lamsoni_w_time     D_8_lamsoni_w_value
0  V345578  295234545       13  [-1000.0, -980.0]  [7.9921875, 11.984375]
1  V346670  329781064       13   [-960.0, -940.0]  [7.9921875, 11.984375]

4.5. 列中使用NaN 的另一种解决方案:

您可以将read_csv 与分隔符; 一起使用,然后将str.split 应用于4.5.iloc 选择的列,并将list 中的每个值转换为float

import pandas as pd
import numpy as np
import io

temp=u"""vin;vorgangid;eventkm;D_8_lamsoni_w_time;D_8_lamsoni_w_value
V345578;295234545;13;-1000.0,-980.0;7.9921875,11.984375
V346670;329781064;13;-960.0,-940.0;7.9921875,11.984375"""
#after testing replace io.StringIO(temp) to filename
df = pd.read_csv(io.StringIO(temp), sep=";")

print (df)
       vin  vorgangid  eventkm D_8_lamsoni_w_time  D_8_lamsoni_w_value
0  V345578  295234545       13     -1000.0,-980.0  7.9921875,11.984375
1  V346670  329781064       13      -960.0,-940.0  7.9921875,11.984375

#split 4.th and 5th column and convert to numpy array
df.iloc[:,3] = df.iloc[:,3].str.split(',').apply(lambda x: [float(i) for i in x])
df.iloc[:,4] = df.iloc[:,4].str.split(',').apply(lambda x: [float(i) for i in x])
print (df)
       vin  vorgangid  eventkm D_8_lamsoni_w_time     D_8_lamsoni_w_value
0  V345578  295234545       13  [-1000.0, -980.0]  [7.9921875, 11.984375]
1  V346670  329781064       13   [-960.0, -940.0]  [7.9921875, 11.984375]

如果需要numpy arrays 而不是lists:

#split 4.th and 5th column and convert to numpy array
df.iloc[:,3] = df.iloc[:,3].str.split(',').apply(lambda x: np.array([float(i) for i in x]))
df.iloc[:,4] = df.iloc[:,4].str.split(',').apply(lambda x: np.array([float(i) for i in x]))
print (df)
       vin  vorgangid  eventkm D_8_lamsoni_w_time     D_8_lamsoni_w_value
0  V345578  295234545       13  [-1000.0, -980.0]  [7.9921875, 11.984375]
1  V346670  329781064       13   [-960.0, -940.0]  [7.9921875, 11.984375]

print (type(df.iloc[0,3]))
<class 'numpy.ndarray'>

我尝试改进您的解决方案:

a=0;
csv_import=pd.read_csv(folder+FileName, ';')
for col in csv_import.columns:
    a += 1
    if type(csv_import.ix[0, col])== str and a>3:
        # string to list of strings
        csv_import[col]=csv_import[col].apply(lambda x: [float(y) for y in x.split(',')])

【讨论】:

感谢您的意见,但如果我错了请纠正我,这看起来比我的方法更乏味。干杯 好的,我尝试改进您的解决方案,请检查我回答中的最后一段。 看起来不错,但我想没有办法避免 for 循环,我只是认为有一种方法可以以某种方式初始化导入,它会自动知道 (',') 分隔值是一个数组 不,如果需要转换以列出一些列,我认为您需要我的第一个解决方案 formaters【参考方案3】:

除了这里的其他更好的答案,它们更特定于 pandas,应该注意的是,Python 本身在字符串处理方面非常强大。您可以将';' 替换为',' 的结果放在StringIO 对象中,然后从那里正常工作:

In [8]: import pandas as pd

In [9]: from cStringIO import StringIO

In [10]: pd.read_csv(StringIO(''.join(l.replace(';', ',') for l in open('stuff.csv'))))
Out[10]: 
                   vin  vorgangid  eventkm  D_8_lamsoni_w_time  \
V345578 295234545   13    -1000.0   -980.0            7.992188   
V346670 329781064   13     -960.0   -940.0            7.992188   

                   D_8_lamsoni_w_value  
V345578 295234545            11.984375  
V346670 329781064            11.984375  

【讨论】:

有趣的方法,这在 Python 3.5 中是如何工作的? import io pd.read_csv(io(''.join(l.replace(';', ',') for l in open('stuff.csv')))) 不起作用 @valenzio 我刚在 3.5.2 上检查过这个,完全一样。 我得到了按摩,没有名为“cStringIO”的模块我必须通过 pip 安装该模块,我感觉它是 python 自带的 @valenzio 抱歉 - 我的措辞不好。代码相同,但导入不同。你需要from io import StringIO 谢谢它现在可以工作了,但是由于某种原因,列名发生了变化,并且对于每个条目,您都会得到一个列。您的方法是我想到的最接近的解决方案。我会尝试理解语法,也许通过一些操作我会找到解决方案。

以上是关于使用两个分隔符将 CSV 导入 pandas的主要内容,如果未能解决你的问题,请参考以下文章

使用 pandas 的 df.to_csv 方法不适用于空格作为分隔符

pandas 常用函数

将逗号小数分隔符转换为数据框中的点

将逗号小数分隔符转换为数据框中的点

Pandas常用方法手册

Pandas DF:如何用分隔符(;CSV 格式)将 '-' 替换为 '_'