根据条件从字符串中删除空格

Removing whitespaces from a string based on a condition

我正在寻求拆分数据方面的帮助。我的数据有千位分隔符的空格,但我的时间戳之间也有空格。

这是数据的示例(当前为 1 列):

Date/Time Var1 Var2 Var3 Var4 Var5 Var6
17/04/2020 00:00:00 133 579.20 31 978.90 377 952.81 179 412.41 203 595.20 70 447.40 
17/04/2020 01:00:00 133 583.70 31 980.40 377 963.41 179 412.41 203 595.20 70 448.20

我需要它看起来像这样:

Date/Time           Var1      Var2     Var3      Var4      Var5      Var6
17/04/2020 00:00:00 133579.20 31978.90 377952.81 179412.41 203595.20 70447.40 
17/04/2020 01:00:00 133583.70 31980.40 377963.41 179412.41 203595.20 70448.20

我认为我正在尝试以一种奇怪且过于复杂的方式解决这个问题。在一个例子中,我删除了所有空格,然后拆分我所做的日期:

df.iloc[:,3] = df.iloc[:,3].str.replace('/2020', '/2020 ').str.replace(':00:00', ':00:00 ')

然后拆分所有数字,我尝试做一些事情,例如读取字符串中的每个字符,一旦找到一个点,就在前面添加一个空格 2 个字符串,但我没能成功工作。

for i in range(len(df)):
    for j in df.iloc[i,:]:
        for k in j:
            if k == '.':
               #to be continued

肯定有更快捷的方法来解决这个问题。谁能帮帮我?

string = """Date/Time Var1 Var2 Var3 Var4 Var5 Var6
17/04/2020 00:00:00 133 579.20 31 978.90 377 952.81 179 412.41 203 595.20 70 447.40 
17/04/2020 01:00:00 133 583.70 31 980.40 377 963.41 179 412.41 203 595.20 70 448.20"""

head = string.split('\n')[0].split(' ')
values = []
import re
value_regex = re.compile(' \d\d\d\.\d*')
timestamp_regex = re.compile('\d\d:\d\d:\d\d')
for line in string.split('\n')[1:]:
    for value in value_regex.findall(line):
        line = line.replace(value, value.replace(' ','')+',')
    for timestamp in timestamp_regex.findall(line):
        line = line.replace(timestamp, timestamp+',')
    value_cur_line =  [sep[1:] if sep.startswith(' ') else sep for sep in line.split(',') if sep.replace(' ','')!='']
    values.append(value_cur_line)

假设 df 是您当前的数据框,并且它有一个名为 'D' 的列(如果不是 'D',请相应更改):

tmplist = df['D'].str.findall(r'(.+?[:.]\S+\s+)').to_list()
tmplist = [ [ e.replace(' ','') if i>0 else e.rstrip() for i, e in enumerate(row) ] for row in tmplist ]
col = ['Date/Time'] + [ 'Var{}'.format(i) for i in range(1,len(tmplist[0])) ]
df = pandas.DataFrame(tmplist, columns=col)

第一行将数据框转换为列表列表,根据需要拆分字符串。使用了一个特定的技巧:点或冒号后跟数字是属于一列的最后一个 space 分隔项(冒号表示时间戳,点表示浮点数)。

第二个从除第一个(时间戳)之外的所有列中删除所有 spaces,它只删除尾随的 spaces。

下一篇根据您的意愿创建列名。

最后一个从列表中重建数据帧。

你可以试试:

out = df[df.columns[0]].str.split(r"\s+")\
    .apply(lambda x: pd.Series([" ".join(x[:2])] + ["{}{}".format(a, b) for a, b in zip(x[2::2], x[3::2])])) \
    .rename(columns={old:new for old, new in enumerate(cols)})

解释:

  1. 使用 df[df.columns[0]] 选择唯一的列后,使用 pandas.Series.str.split 根据所有 space 拆分此列。正则表达式很简单 \s+: df[df.columns[0]].str.split(r"\s+")
  2. 使用 apply 在每行上应用自定义函数。
    1. 首先通过将前 2 个元素与 space 合并来重新创建日期,转换为日期并将其包装在列表中:[pd.Timestamp(" ".join(x[:2]))]
    2. 合并所有其他值 2-by2 使用 zip. This discussion 提供更多详细信息。

[float("{}{}".format(a, b)) for a, b in zip(x[2::2], x[3::2])]

  1. 将此列表转换为 pd.Series 包装步骤 2.1 和 2.2 的结果。

  2. 使用 rename 重命名列。字典理解让我们执行预期的结果:.rename(columns={old:new for old, new in enumerate(cols)})


完整代码+插图:

print(df)
#              Date/Time Var1 Var2 Var3 Var4 Var5 Var6
# 0  17/04/2020 00:00:00 133 579.20 31 978.90 377 9...
# 1  17/04/2020 01:00:00 133 583.70 31 980.40 377 9...

# Step 1
print(df[df.columns[0]].str.split(r"\s+"))
# 0    [17/04/2020, 00:00:00, 133, 579.20, 31, 978.90...
# 1    [17/04/2020, 01:00:00, 133, 583.70, 31, 980.40...
# Name: Date/Time Var1 Var2 Var3 Var4 Var5 Var6, dtype: object

# Step 2.1
print(df[df.columns[0]].str.split(r"\s+")
      .apply(lambda x: [pd.Timestamp(" ".join(x[:2]))]))
# 0    [2020-04-17 00:00:00]
# 1    [2020-04-17 01:00:00]
# Name: Date/Time Var1 Var2 Var3 Var4 Var5 Var6, dtype: object

# Step 2.2
print(df[df.columns[0]].str.split(r"\s+")
      .apply(lambda x: [float("{}{}".format(a, b)) for a, b in zip(x[2::2], x[3::2])]))
# 0    [133579.2, 31978.9, 377952.81, 179412.41, 2035...
# 1    [133583.7, 31980.4, 377963.41, 179412.41, 2035...
# Name: Date/Time Var1 Var2 Var3 Var4 Var5 Var6, dtype: object

# Step 2.3
print(df[df.columns[0]].str.split(r"\s+")
      .apply(lambda x: pd.Series([pd.Timestamp(" ".join(x[:2]))] + [float("{}{}".format(a, b)) for a, b in zip(x[2::2], x[3::2])])))
#                     0         1        2          3          4         5        6
# 0 2020-04-17 00:00:00  133579.2  31978.9  377952.81  179412.41  203595.2  70447.4
# 1 2020-04-17 01:00:00  133583.7  31980.4  377963.41  179412.41  203595.2  70448.2


# Step 3
print(df.columns[0].split(" "))
# ['Date/Time', 'Var1', 'Var2', 'Var3', 'Var4', 'Var5', 'Var6']


out = df[df.columns[0]].str.split(r"\s+")\
    .apply(lambda x: pd.Series([pd.Timestamp(" ".join(x[:2]))] + [float("{}{}".format(a, b)) for a, b in zip(x[2::2], x[3::2])])) \
    .rename(columns={old: new for old, new in enumerate(df.columns[0].split(" "))})
print(out)
#             Date/Time      Var1     Var2       Var3       Var4      Var5     Var6
# 0 2020-04-17 00:00:00  133579.2  31978.9  377952.81  179412.41  203595.2  70447.4
# 1 2020-04-17 01:00:00  133583.7  31980.4  377963.41  179412.41  203595.2  70448.2


print(out.dtypes)
# Date/Time    datetime64[ns]
# Var1                float64
# Var2                float64
# Var3                float64
# Var4                float64
# Var5                float64
# Var6                float64
# dtype: object