搜索pandas系列的值,并在该值处拆分系列

时间:2013-11-20 04:43:43

标签: python csv python-3.x pandas

Python 3.3.3 熊猫0.12.0

我有一个单列.csv文件,其中有数百个浮点值由任意字符串分隔(该字符串包含字母编辑:,并且将运行以运行)。我是一个熊猫初学者,希望找到一种方法来加载.csv文件并将浮点值分成两个列,在该字符串的水平。

我太困在第一部分(寻找字符串),我还没有能够在第二部分工作,我认为应该更容易。

到目前为止,我一直在尝试使用raw = pandas.read_csv('myfile.csv', squeeze=True),然后使用类似raw.str.findall('[a-z]')的内容,但我没有太多运气。如果有人可以伸出援助之手,我真的很感激。我打算在许多类似的.csv文件上使用这个过程,所以我希望找到一种相当自动化的方法来执行任务。

示例input.csv:

123.4932
239.348
912.098098989
49391.1093
....
This is a fake string that splits the data.
....
1323.4942
2445.34223
914432.4
495391.1093090

所需的最终DataFrame:

Column A         Column B
123.4932         1323.4942
239.348          2445.34223
912.098098989    914432.4
49391.1093       495391.1093090
...              ...

再次感谢你能指出我正确的方向。


20131123 编辑:感谢您迄今为止的回复。更新以反映拆分字符串不会保持不变,因此我声明我一直在尝试使用正则表达式raw.str.findall('[a-z]')而不是使用.contains来找到解决方案。

此时我的解决方案是只读取.csv文件并与re分开,累积到列表中,然后将它们加载到pandas中。

import pandas as pd
import re

raw = open('myfile.csv', 'r').read().split('\n')
df = pd.DataFrame()
keeper = []
counter = 0

# Iterate through the rows. Consecutive rows that can be made into float are accumulated.
for row in raw:
    try:
        keeper.append(float(row))
    except:
        if keeper:
            df = pd.concat([df, pd.DataFrame(keeper, columns = [counter] )], axis = 1)
            counter += 1            
        keeper = []

# Get the last column, assuming the file hasn't ended on a line
# that will trigger the exception in the above loop.
if keeper:
    df = pd.concat([df, pd.DataFrame(keeper, columns = [counter] )], axis = 1)

df.describe()

感谢您提出进一步的建议。

20180729 EDIT2:使用itertools.groupby的另一种可能解决方案:

import io
import itertools
import re

import numpy as np
import pandas as pd

txt = """123.4932
239.348
912.098098989
49391.1093
This is a fake string that splits the data.
1323.4942
2445.34223
914432.4
495391.1093090
fake again
31323.4942
42445.34223
2914432.4
5495391.1093090
23423432""".splitlines()

groups = itertools.groupby(
        txt,
        key=lambda x: not re.match('^[\d.]+$', x)
)
df = pd.concat(
    (pd.Series(list(g)) for k, g in groups if not k),
    axis=1
)
print(df)

2 个答案:

答案 0 :(得分:0)

如果您知道只有两列,那么您可以执行类似

的操作
>>> ser = pd.read_csv("colsplit.csv", header=None, squeeze=True)
>>> split_at = ser.str.contains("fake string that splits").idxmax()
>>> parts = [ser[:split_at], ser[split_at+1:]]
>>> parts = [part.reset_index(drop=True) for part in parts]
>>> df = pd.concat(parts, axis=1)
>>> df.columns = ["Column A", "Column B"]
>>> df
        Column A            Column B
0       123.4932                ....
1        239.348           1323.4942
2  912.098098989          2445.34223
3     49391.1093            914432.4
4           ....      495391.1093090
5            NaN  extra test element

如果你有任意数量的地方需要拆分,那么你可以使用布尔系列/ shift / cumsum / groupby模式,但如果没有它就可以逃脱,那就更好了。

(PS:我确信有比idxmax更好的方法,但对于我的生活,我不记得现在找到第一个True的成语。split_at[split_at].index[0]会这样做,但我不确定那会好得多。)

答案 1 :(得分:0)

使用numpy.split()

import io
import numpy as np
import pandas as pd

txt = """123.4932
239.348
912.098098989
49391.1093
This is a fake string that splits the data.
1323.4942
2445.34223
914432.4
495391.1093090
fake again
31323.4942
42445.34223
2914432.4
5495391.1093090
23423432"""

s = pd.read_csv(io.BytesIO(txt), header=None, squeeze=True)
mask = s.str.contains("fake")
pos = np.where(mask)[0]
pos -= np.arange(len(pos))

arrs = [s.reset_index(drop=True) for s in np.split(s[~mask], pos)]
pd.concat(arrs, axis=1, ignore_index=True).astype(float)

输出:

               0               1                2
0       123.4932       1323.4942       31323.4942
1        239.348      2445.34223      42445.34223
2  912.098098989        914432.4        2914432.4
3     49391.1093  495391.1093090  5495391.1093090
4            NaN             NaN         23423432