【问题标题】:Search pandas series for value and split series at that value在熊猫系列中搜索值并在该值处拆分系列
【发布时间】:2013-11-20 04:43:43
【问题描述】:

Python 3.3.3 熊猫 0.12.0

我有一个单列 .csv 文件,其中包含由任意字符串分隔的数百个浮点值(该字符串包含字母编辑:并且会因运行而异)。我是 pandas 初学者,希望找到一种方法来加载该 .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

所需的最终数据帧:

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)

【问题讨论】:

  • 分隔符到底是什么?
  • 不幸的是 read_csv 的 lineterminator arg 不允许你这样做(还没有?)ValueError: Only length-1 line terminators supported
  • 是的,不幸的是,pandas 仍然无法处理非常 非结构化的数据。在这种情况下,解决方案涉及文本编辑器或(更方便的)Unix 命令行工具。
  • 这将是我的连续组的另一个用例enhancement,尽管没有它我们可以轻松完成这个。
  • 实际的分隔符会有所不同,但始终是以几个单词开头的句子,可能是几个数字和符号。应该总是失败.match('\d+')

标签: python csv python-3.x pandas


【解决方案1】:

使用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

【讨论】:

    【解决方案2】:

    如果你知道你只有两列,那么你可以做类似的事情

    >>> 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
    

    如果您有任意数量的拆分位置,那么您可以使用布尔型 Series/shift/cumsum/groupby 模式,但如果您可以不使用它,那就更好了。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-30
      • 1970-01-01
      • 2016-04-19
      • 2017-07-30
      相关资源
      最近更新 更多