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

3

我有一个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])
3个回答

4
除了其他更加针对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
@valenzio 我刚在3.5.2上检查了一下,结果完全一样。 - Ami Tavory
我收到了这条消息:“No module named 'cStringIO'”。我需要通过pip安装该模块吗?我有一种感觉它应该随Python一起安装。 - valenzio
@valenzio 抱歉 - 我的措辞不当。代码是相同的,但导入方式不同。你需要 from io import StringIO - Ami Tavory
谢谢,现在它可以工作了,但由于某种原因,列名被移位了,每个条目只有一个列。你的方法是我想到的最接近的解决方案。我会尝试理解语法,也许通过一些操作我会找到解决方案。 - valenzio
@valenzio 好的,祝你好运。如果你发现了有趣的东西,随时可以发布(对我来说,它似乎有效,但总有学习的东西)。 - Ami Tavory

3

首先使用 ; 作为分隔符读取 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]

谢谢您的建议。我有两个评论: 1)如果您有超过2列,我猜第20行可以打包到一个for循环中,但这样它基本上变成了与我的方法相同,对吗? 2)我认为最后你仍然会得到一个字符串列表,例如type(df.ix [0,4][0]) == 'str' - valenzio
@valenzio,请查看更新部分 - 我已经完全重写了代码并回答了你的两个问题。 - MaxU - stand with Ukraine
谢谢,伙计,这看起来好多了,但如果你有100个条目在第67和68行,你仍然需要两个for循环,我正在寻找类似Ami Tavory建议的解决方案。基本上是一个带有正确参数的导入命令。 - valenzio
@valenzio,不需要额外的循环。 - MaxU - stand with Ukraine
@MaxU,这样想:我提供的数据只是为了更易读而已。实际上,我有100多个不同名称的列,因此我需要一个for循环来创建“num_cols”,另一个for循环来分配不同的列与新的数据类型。 - valenzio
@valenzio,这就是重点!df.columns.difference(['vin','vorgangid','eventkm']) - 将给出除了 ['vin','vorgangid','eventkm'] 之外的__所有__列,而 df[num_cols] = (df[num_cols].apply(...) 将在一步中处理 num_cols 列中的__所有__列。 - MaxU - stand with Ukraine

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 分隔符为 ;,然后对通过 iloc 选择的 4.5. 列应用 str.split 并将每个值转换为 float 类型的 list

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数组而不是列表:
#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(',')])

谢谢您的输入,但如果我错了,请纠正我,这看起来比我的方法更繁琐。干杯 - valenzio
好的,我尝试改进您的解决方案,请查看我的答案中的最后一段。 - jezrael
看起来不错,但我猜想无法避免使用for循环,我只是认为有一种方法可以初始化导入方式,让它自动知道(',')分隔的值是一个数组。 - valenzio
不,如果需要将某些列转换为列表,则我认为您需要使用我的第一个解决方案,其中包含“formaters”。 - jezrael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接