Pandas 子字符串 DataFrame 列
Pandas substring DataFrame column
我有一个 pandas DataFrame,有一个名为 positions
的列,其中包含具有以下示例语法的字符串值:
[{'y': 49, 'x': 44}, {'y': 78, 'x': 31}]
[{'y': 1, 'x': 63}, {'y': 0, 'x': 23}]
[{'y': 54, 'x': 9}, {'y': 78, 'x': 3}]
我想在我的 pandas DataFrame 中创建四个新列,y_start
、x_start
、y_end
、x_end
,它们仅提取数字。
例如对于第一行的示例,我的新列将具有以下值:
y_start
= 49
x_start
= 44
y_end
= 78
x_end
= 31
总而言之,我只想提取第一次、第二次、第三次和第四次出现的数字,并将它们保存到单独的列中。
将字符串转换为对象:
import ast
df['positions'] = df['positions'].apply(ast.literal_eval)
这是一种方式:
df1 = pd.DataFrame.from_records(pd.DataFrame.from_records(df.positions)[0]).rename(columns={"x":"x_start", "y":"y_start"})
df2 = pd.DataFrame.from_records(pd.DataFrame.from_records(df.positions)[1]).rename(columns={"x":"x_end", "y":"y_end"})
df_new = pd.concat([df1, df2], axis=1)
另一个,更简洁一点:
df1 = pd.DataFrame(df.positions.to_list())[0].apply(pd.Series).rename(columns={"x":"x_start", "y":"y_start"})
df2 = pd.DataFrame(df.positions.to_list())[1].apply(pd.Series).rename(columns={"x":"x_end", "y":"y_end"})
df_new = pd.concat([df1, df2], axis=1)
我不知道这些方法的时间或内存性能如何比较。
输出(任一方法):
y_start x_start y_end x_end
0 49 44 78 31
1 1 63 0 23
2 54 9 78 3
不太干净,但工作方式是编写自定义函数并应用 lambda,假设所有行都遵循问题中提供的相同模式:
### custom function
def startEndxy(x):
x = x.split(':')
return x[1].split(',')[0].replace(' ', ''), x[2].split('},')[0].replace(' ', ''), x[3].split(',')[0].replace(' ', ''), x[4].split('}')[0].replace(' ', '')
### columns creations
df['y_start'] = df['positions'].apply(lambda x: startEndxy(x)[0])
df['x_start'] = df['positions'].apply(lambda x: startEndxy(x)[1])
df['y_end'] = df['positions'].apply(lambda x: startEndxy(x)[2])
df['x_end'] = df['positions'].apply(lambda x: startEndxy(x)[3])
它应该给你这个输出:
Output
- 第一个问题是将字符串转换回字典,这可以通过
ast.literal_eval
完成
- 使用
pandas.DataFrame
构造函数分隔列表以分隔列,因为它比使用 .apply(pd.Series)
更快
- 将每列中的字典转换为每个键的单独列,同时使用
pandas.json_normalize
, .rename
the columns, and .concat
它们。
- Splitting dictionary/list inside a Pandas Column into Separate Columns 没有完全回答这个问题,但它是相似的。
- 如果数据是从 csv 加载的,请将
converters
参数与 .read_csv
一起使用。
df = pd.read_csv('data.csv', converters={'str_column': literal_eval})
import pandas as pd
from ast import literal_eval
# dataframe
data = {'data': ["[{'y': 49, 'x': 44}, {'y': 78, 'x': 31}]", "[{'y': 1, 'x': 63}, {'y': 0, 'x': 23}]", "[{'y': 54, 'x': 9}, {'y': 78, 'x': 3}]"]}
df = pd.DataFrame(data)
# convert the strings in the data column to dicts
df.data = df.data.apply(literal_eval)
# separate the strings into separate columns
df[['start', 'end']] = pd.DataFrame(df.data.tolist(), index=df.index)
# use json_normalize to convert the dicts to separate columns and join the dataframes with concat
cleaned = pd.concat([pd.json_normalize(df.start).rename(lambda x: f'{x}_start', axis=1), pd.json_normalize(df.end).rename(lambda x: f'{x}_end', axis=1)], axis=1)
# display(cleaned)
y_start x_start y_end x_end
0 49 44 78 31
1 1 63 0 23
2 54 9 78 3
首先重建你的系列
df = pd.DataFrame(df['position'].tolist()).rename(columns={0: 'starts', 1:'ends'})
starts ends
0 {'y': 54, 'x': 9} {'y': 78, 'x': 3}
1 {'y': 1, 'x': 63} {'y': 0, 'x': 23}
2 {'y': 54, 'x': 9} {'y': 78, 'x': 3}
然后分配开始和结束列
starts = pd.DataFrame(df['starts'].tolist()).rename(columns={'y': 'y_start', 'x': 'x_start'})
ends = pd.DataFrame(df['end'].tolist()).rename(columns={'y': 'y_start', 'x': 'x_start'})
df = pd.concat([starts, ends], axis=1)
y_start x_start y_end x_end
0 54 9 78 3
1 1 63 0 23
2 54 9 78 3
我有一个 pandas DataFrame,有一个名为 positions
的列,其中包含具有以下示例语法的字符串值:
[{'y': 49, 'x': 44}, {'y': 78, 'x': 31}]
[{'y': 1, 'x': 63}, {'y': 0, 'x': 23}]
[{'y': 54, 'x': 9}, {'y': 78, 'x': 3}]
我想在我的 pandas DataFrame 中创建四个新列,y_start
、x_start
、y_end
、x_end
,它们仅提取数字。
例如对于第一行的示例,我的新列将具有以下值:
y_start
= 49
x_start
= 44
y_end
= 78
x_end
= 31
总而言之,我只想提取第一次、第二次、第三次和第四次出现的数字,并将它们保存到单独的列中。
将字符串转换为对象:
import ast
df['positions'] = df['positions'].apply(ast.literal_eval)
这是一种方式:
df1 = pd.DataFrame.from_records(pd.DataFrame.from_records(df.positions)[0]).rename(columns={"x":"x_start", "y":"y_start"})
df2 = pd.DataFrame.from_records(pd.DataFrame.from_records(df.positions)[1]).rename(columns={"x":"x_end", "y":"y_end"})
df_new = pd.concat([df1, df2], axis=1)
另一个,更简洁一点:
df1 = pd.DataFrame(df.positions.to_list())[0].apply(pd.Series).rename(columns={"x":"x_start", "y":"y_start"})
df2 = pd.DataFrame(df.positions.to_list())[1].apply(pd.Series).rename(columns={"x":"x_end", "y":"y_end"})
df_new = pd.concat([df1, df2], axis=1)
我不知道这些方法的时间或内存性能如何比较。
输出(任一方法):
y_start x_start y_end x_end
0 49 44 78 31
1 1 63 0 23
2 54 9 78 3
不太干净,但工作方式是编写自定义函数并应用 lambda,假设所有行都遵循问题中提供的相同模式:
### custom function
def startEndxy(x):
x = x.split(':')
return x[1].split(',')[0].replace(' ', ''), x[2].split('},')[0].replace(' ', ''), x[3].split(',')[0].replace(' ', ''), x[4].split('}')[0].replace(' ', '')
### columns creations
df['y_start'] = df['positions'].apply(lambda x: startEndxy(x)[0])
df['x_start'] = df['positions'].apply(lambda x: startEndxy(x)[1])
df['y_end'] = df['positions'].apply(lambda x: startEndxy(x)[2])
df['x_end'] = df['positions'].apply(lambda x: startEndxy(x)[3])
它应该给你这个输出: Output
- 第一个问题是将字符串转换回字典,这可以通过
ast.literal_eval
完成
- 使用
pandas.DataFrame
构造函数分隔列表以分隔列,因为它比使用.apply(pd.Series)
更快 - 将每列中的字典转换为每个键的单独列,同时使用
pandas.json_normalize
,.rename
the columns, and.concat
它们。 - Splitting dictionary/list inside a Pandas Column into Separate Columns 没有完全回答这个问题,但它是相似的。
- 如果数据是从 csv 加载的,请将
converters
参数与.read_csv
一起使用。df = pd.read_csv('data.csv', converters={'str_column': literal_eval})
import pandas as pd
from ast import literal_eval
# dataframe
data = {'data': ["[{'y': 49, 'x': 44}, {'y': 78, 'x': 31}]", "[{'y': 1, 'x': 63}, {'y': 0, 'x': 23}]", "[{'y': 54, 'x': 9}, {'y': 78, 'x': 3}]"]}
df = pd.DataFrame(data)
# convert the strings in the data column to dicts
df.data = df.data.apply(literal_eval)
# separate the strings into separate columns
df[['start', 'end']] = pd.DataFrame(df.data.tolist(), index=df.index)
# use json_normalize to convert the dicts to separate columns and join the dataframes with concat
cleaned = pd.concat([pd.json_normalize(df.start).rename(lambda x: f'{x}_start', axis=1), pd.json_normalize(df.end).rename(lambda x: f'{x}_end', axis=1)], axis=1)
# display(cleaned)
y_start x_start y_end x_end
0 49 44 78 31
1 1 63 0 23
2 54 9 78 3
首先重建你的系列
df = pd.DataFrame(df['position'].tolist()).rename(columns={0: 'starts', 1:'ends'})
starts ends
0 {'y': 54, 'x': 9} {'y': 78, 'x': 3}
1 {'y': 1, 'x': 63} {'y': 0, 'x': 23}
2 {'y': 54, 'x': 9} {'y': 78, 'x': 3}
然后分配开始和结束列
starts = pd.DataFrame(df['starts'].tolist()).rename(columns={'y': 'y_start', 'x': 'x_start'})
ends = pd.DataFrame(df['end'].tolist()).rename(columns={'y': 'y_start', 'x': 'x_start'})
df = pd.concat([starts, ends], axis=1)
y_start x_start y_end x_end
0 54 9 78 3
1 1 63 0 23
2 54 9 78 3