删除 pandas DataFrame 列中字符串条目的结尾
Remove ends of string entries in pandas DataFrame column
我有一个 pandas 数据框,其中一列是文件列表
import pandas as pd
df = pd.read_csv('fname.csv')
df.head()
filename A B C
fn1.txt 2 4 5
fn2.txt 1 2 1
fn3.txt ....
....
我想从 filename
中的每个条目中删除文件扩展名 .txt
。我该如何做到这一点?
我试过了:
df['filename'] = df['filename'].map(lambda x: str(x)[:-4])
但是当我随后使用 df.head()
查看列条目时,没有任何改变。
如何做到这一点?
您可以使用 str.rstrip
删除结尾:
df['filename'] = df['filename'].str.rstrip('.txt')
应该可以
我想你可以使用 str.replace
with regex .txt$'
( $
- matches the end of the string):
import pandas as pd
df = pd.DataFrame({'A': {0: 2, 1: 1},
'C': {0: 5, 1: 1},
'B': {0: 4, 1: 2},
'filename': {0: "txt.txt", 1: "x.txt"}},
columns=['filename','A','B', 'C'])
print df
filename A B C
0 txt.txt 2 4 5
1 x.txt 1 2 1
df['filename'] = df['filename'].str.replace(r'.txt$', '')
print df
filename A B C
0 txt 2 4 5
1 x 1 2 1
df['filename'] = df['filename'].map(lambda x: str(x)[:-4])
print df
filename A B C
0 txt 2 4 5
1 x 1 2 1
df['filename'] = df['filename'].str[:-4]
print df
filename A B C
0 txt 2 4 5
1 x 1 2 1
编辑:
rstrip
可以去除更多的字符,如果字符串的末尾包含一些条纹字符串的字符(在本例中为.
、t
、x
):
示例:
print df
filename A B C
0 txt.txt 2 4 5
1 x.txt 1 2 1
df['filename'] = df['filename'].str.rstrip('.txt')
print df
filename A B C
0 2 4 5
1 1 2 1
您可能需要:
df['filename'] = df.apply(lambda x: x['filename'][:-4], axis = 1)
使用列表理解
df['filename'] = [x[:-4] for x in df['filename']]
更新 2021 + 速度测试
从pandas 1.4开始,实现了str.removesuffix, the pandas.Series.str.removesuffix的等价物,所以可以使用
df['filename'].str.removesuffix('.txt')
速度测试
tl;dr:最快的是
dat["fname"].map(lambda x: x[:-4] if x[-4:] == ".txt" else x)
在速度测试中,我想考虑这个SO页面中收集的不同方法。我排除了 rstrip
,因为它也会去除 .txt
以外的结尾,并且由于正则表达式包含条件,因此修改其他函数也是公平的,以便它们仅在它们删除最后 4 个字符时是 .txt
.
测试代码为
import pandas as pd
import time
ITER = 10
def rm_re(dat: pd.DataFrame) -> pd.Series:
"""Use regular expression."""
return dat["fname"].str.replace(r'.txt$', '', regex=True)
def rm_map(dat: pd.DataFrame) -> pd.Series:
"""Use pandas map, find occurrences and remove with []"""
where = dat["fname"].str.endswith(".txt")
dat.loc[where, "fname"] = dat["fname"].map(lambda x: x[:-4])
return dat["fname"]
def rm_map2(dat: pd.DataFrame) -> pd.Series:
"""Use pandas map with lambda conditional."""
return dat["fname"].map(lambda x: x[:-4] if x[-4:] == ".txt" else x)
def rm_apply_str_suffix(dat: pd.DataFrame) -> pd.Series:
"""Use str method suffix with pandas apply"""
return dat["fname"].apply(str.removesuffix, args=(".txt",))
def rm_suffix(dat: pd.DataFrame) -> pd.Series:
"""Use pandas removesuffix from version 1.6"""
return dat["fname"].str.removesuffix(".txt")
functions = [rm_map2, rm_apply_str_suffix, rm_map, rm_suffix, rm_re]
for base in range(12, 23):
size = 2**base
data = pd.DataFrame({"fname": ["fn"+str(i) for i in range(size)]})
data.update(data.sample(frac=.5)["fname"]+".txt")
for func in functions:
diff = 0
for _ in range(ITER):
data_copy = data.copy()
start = time.process_time()
func(data_copy)
diff += time.process_time() - start
print(diff, end="\t")
输出绘制如下:
从图中可以看出,最慢的解决方案是正则表达式,最快的是带条件的 pandas.Series.map
。在 pandas 的更高版本中,这可能会改变,我希望 pandas.Series.str.removesuffix
有所改进,因为它在矢量化方面具有更大的潜力。
Pandas 必须从 2021-11-30 开始从源安装,因为 1.4 版仅处于开发阶段。我按照 pandas dev repo 中的说明安装了它,方法是克隆项目并使用 python setup.py install
.
安装
我的机器:
- AMD Ryzen 5 2400G 配备 Radeon Vega 显卡,3.60 GHz
- Windows 10 20H2
- Python 3.10.0, pandas.版本 '1.4.0.dev0+1267.gaee662a7e3', numpy.版本 '1.21.4'
我有一个 pandas 数据框,其中一列是文件列表
import pandas as pd
df = pd.read_csv('fname.csv')
df.head()
filename A B C
fn1.txt 2 4 5
fn2.txt 1 2 1
fn3.txt ....
....
我想从 filename
中的每个条目中删除文件扩展名 .txt
。我该如何做到这一点?
我试过了:
df['filename'] = df['filename'].map(lambda x: str(x)[:-4])
但是当我随后使用 df.head()
查看列条目时,没有任何改变。
如何做到这一点?
您可以使用 str.rstrip
删除结尾:
df['filename'] = df['filename'].str.rstrip('.txt')
应该可以
我想你可以使用 str.replace
with regex .txt$'
( $
- matches the end of the string):
import pandas as pd
df = pd.DataFrame({'A': {0: 2, 1: 1},
'C': {0: 5, 1: 1},
'B': {0: 4, 1: 2},
'filename': {0: "txt.txt", 1: "x.txt"}},
columns=['filename','A','B', 'C'])
print df
filename A B C
0 txt.txt 2 4 5
1 x.txt 1 2 1
df['filename'] = df['filename'].str.replace(r'.txt$', '')
print df
filename A B C
0 txt 2 4 5
1 x 1 2 1
df['filename'] = df['filename'].map(lambda x: str(x)[:-4])
print df
filename A B C
0 txt 2 4 5
1 x 1 2 1
df['filename'] = df['filename'].str[:-4]
print df
filename A B C
0 txt 2 4 5
1 x 1 2 1
编辑:
rstrip
可以去除更多的字符,如果字符串的末尾包含一些条纹字符串的字符(在本例中为.
、t
、x
):
示例:
print df
filename A B C
0 txt.txt 2 4 5
1 x.txt 1 2 1
df['filename'] = df['filename'].str.rstrip('.txt')
print df
filename A B C
0 2 4 5
1 1 2 1
您可能需要:
df['filename'] = df.apply(lambda x: x['filename'][:-4], axis = 1)
使用列表理解
df['filename'] = [x[:-4] for x in df['filename']]
更新 2021 + 速度测试
从pandas 1.4开始,实现了str.removesuffix, the pandas.Series.str.removesuffix的等价物,所以可以使用
df['filename'].str.removesuffix('.txt')
速度测试
tl;dr:最快的是
dat["fname"].map(lambda x: x[:-4] if x[-4:] == ".txt" else x)
在速度测试中,我想考虑这个SO页面中收集的不同方法。我排除了 rstrip
,因为它也会去除 .txt
以外的结尾,并且由于正则表达式包含条件,因此修改其他函数也是公平的,以便它们仅在它们删除最后 4 个字符时是 .txt
.
测试代码为
import pandas as pd
import time
ITER = 10
def rm_re(dat: pd.DataFrame) -> pd.Series:
"""Use regular expression."""
return dat["fname"].str.replace(r'.txt$', '', regex=True)
def rm_map(dat: pd.DataFrame) -> pd.Series:
"""Use pandas map, find occurrences and remove with []"""
where = dat["fname"].str.endswith(".txt")
dat.loc[where, "fname"] = dat["fname"].map(lambda x: x[:-4])
return dat["fname"]
def rm_map2(dat: pd.DataFrame) -> pd.Series:
"""Use pandas map with lambda conditional."""
return dat["fname"].map(lambda x: x[:-4] if x[-4:] == ".txt" else x)
def rm_apply_str_suffix(dat: pd.DataFrame) -> pd.Series:
"""Use str method suffix with pandas apply"""
return dat["fname"].apply(str.removesuffix, args=(".txt",))
def rm_suffix(dat: pd.DataFrame) -> pd.Series:
"""Use pandas removesuffix from version 1.6"""
return dat["fname"].str.removesuffix(".txt")
functions = [rm_map2, rm_apply_str_suffix, rm_map, rm_suffix, rm_re]
for base in range(12, 23):
size = 2**base
data = pd.DataFrame({"fname": ["fn"+str(i) for i in range(size)]})
data.update(data.sample(frac=.5)["fname"]+".txt")
for func in functions:
diff = 0
for _ in range(ITER):
data_copy = data.copy()
start = time.process_time()
func(data_copy)
diff += time.process_time() - start
print(diff, end="\t")
输出绘制如下:
从图中可以看出,最慢的解决方案是正则表达式,最快的是带条件的 pandas.Series.map
。在 pandas 的更高版本中,这可能会改变,我希望 pandas.Series.str.removesuffix
有所改进,因为它在矢量化方面具有更大的潜力。
Pandas 必须从 2021-11-30 开始从源安装,因为 1.4 版仅处于开发阶段。我按照 pandas dev repo 中的说明安装了它,方法是克隆项目并使用 python setup.py install
.
我的机器:
- AMD Ryzen 5 2400G 配备 Radeon Vega 显卡,3.60 GHz
- Windows 10 20H2
- Python 3.10.0, pandas.版本 '1.4.0.dev0+1267.gaee662a7e3', numpy.版本 '1.21.4'