根据列值删除 Pandas 中的 DataFrame 行
- 2024-12-04 08:56:00
- admin 原创
- 146
问题描述:
我有以下数据框:
daysago line_race rating rw wrating
line_date
2007-03-31 62 11 56 1.000000 56.000000
2007-03-10 83 11 67 1.000000 67.000000
2007-02-10 111 9 66 1.000000 66.000000
2007-01-13 139 10 83 0.880678 73.096278
2006-12-23 160 10 88 0.793033 69.786942
2006-11-09 204 9 52 0.636655 33.106077
2006-10-22 222 8 66 0.581946 38.408408
2006-09-29 245 9 70 0.518825 36.317752
2006-09-16 258 11 68 0.486226 33.063381
2006-08-30 275 8 72 0.446667 32.160051
2006-02-11 475 5 65 0.164591 10.698423
2006-01-13 504 0 70 0.142409 9.968634
2006-01-02 515 0 64 0.134800 8.627219
2005-12-06 542 0 70 0.117803 8.246238
2005-11-29 549 0 70 0.113758 7.963072
2005-11-22 556 0 -1 0.109852 -0.109852
2005-11-01 577 0 -1 0.098919 -0.098919
2005-10-20 589 0 -1 0.093168 -0.093168
2005-09-27 612 0 -1 0.083063 -0.083063
2005-09-07 632 0 -1 0.075171 -0.075171
2005-06-12 719 0 69 0.048690 3.359623
2005-05-29 733 0 -1 0.045404 -0.045404
2005-05-02 760 0 -1 0.039679 -0.039679
2005-04-02 790 0 -1 0.034160 -0.034160
2005-03-13 810 0 -1 0.030915 -0.030915
2004-11-09 934 0 -1 0.016647 -0.016647
我需要删除line_race
等于的行0
。最有效的方法是什么?
解决方案 1:
如果我理解正确的话,它应该很简单:
df = df[df.line_race != 0]
解决方案 2:
但是对于任何未来的旁路者,你可以提到,df = df[df.line_race != 0]
在尝试过滤None
/缺失值时不会执行任何操作。
是否有效:
df = df[df.line_race != 0]
不做任何事情:
df = df[df.line_race != None]
是否有效:
df = df[df.line_race.notnull()]
解决方案 3:
只需添加另一个解决方案,如果您使用新的熊猫评估员,则特别有用,其他解决方案将取代原始的熊猫并失去评估员
df.drop(df.loc[df['line_race']==0].index, inplace=True)
解决方案 4:
如果有多个值和 str dtype
我使用以下方法过滤掉col中的给定值:
def filter_rows_by_values(df, col, values):
return df[~df[col].isin(values)]
例子:
在 DataFrame 中我想删除列“str”中值为“b”和“c”的行
df = pd.DataFrame({"str": ["a","a","a","a","b","b","c"], "other": [1,2,3,4,5,6,7]})
df
str other
0 a 1
1 a 2
2 a 3
3 a 4
4 b 5
5 b 6
6 c 7
filter_rows_by_values(df, "str", ["b","c"])
str other
0 a 1
1 a 2
2 a 3
3 a 4
解决方案 5:
如果您想根据列的多个值删除行,您可以使用:
df[(df.line_race != 0) & (df.line_race != 10)]
删除所有值为 0 和 10 的行line_race
。
解决方案 6:
虽然前面的答案与我要做的几乎相似,但使用索引方法不需要使用另一个索引方法 .loc()。它可以以类似但精确的方式完成
df.drop(df.index[df['line_race'] == 0], inplace = True)
解决方案 7:
最好的方法是使用布尔掩码:
In [56]: df
Out[56]:
line_date daysago line_race rating raw wrating
0 2007-03-31 62 11 56 1.000 56.000
1 2007-03-10 83 11 67 1.000 67.000
2 2007-02-10 111 9 66 1.000 66.000
3 2007-01-13 139 10 83 0.881 73.096
4 2006-12-23 160 10 88 0.793 69.787
5 2006-11-09 204 9 52 0.637 33.106
6 2006-10-22 222 8 66 0.582 38.408
7 2006-09-29 245 9 70 0.519 36.318
8 2006-09-16 258 11 68 0.486 33.063
9 2006-08-30 275 8 72 0.447 32.160
10 2006-02-11 475 5 65 0.165 10.698
11 2006-01-13 504 0 70 0.142 9.969
12 2006-01-02 515 0 64 0.135 8.627
13 2005-12-06 542 0 70 0.118 8.246
14 2005-11-29 549 0 70 0.114 7.963
15 2005-11-22 556 0 -1 0.110 -0.110
16 2005-11-01 577 0 -1 0.099 -0.099
17 2005-10-20 589 0 -1 0.093 -0.093
18 2005-09-27 612 0 -1 0.083 -0.083
19 2005-09-07 632 0 -1 0.075 -0.075
20 2005-06-12 719 0 69 0.049 3.360
21 2005-05-29 733 0 -1 0.045 -0.045
22 2005-05-02 760 0 -1 0.040 -0.040
23 2005-04-02 790 0 -1 0.034 -0.034
24 2005-03-13 810 0 -1 0.031 -0.031
25 2004-11-09 934 0 -1 0.017 -0.017
In [57]: df[df.line_race != 0]
Out[57]:
line_date daysago line_race rating raw wrating
0 2007-03-31 62 11 56 1.000 56.000
1 2007-03-10 83 11 67 1.000 67.000
2 2007-02-10 111 9 66 1.000 66.000
3 2007-01-13 139 10 83 0.881 73.096
4 2006-12-23 160 10 88 0.793 69.787
5 2006-11-09 204 9 52 0.637 33.106
6 2006-10-22 222 8 66 0.582 38.408
7 2006-09-29 245 9 70 0.519 36.318
8 2006-09-16 258 11 68 0.486 33.063
9 2006-08-30 275 8 72 0.447 32.160
10 2006-02-11 475 5 65 0.165 10.698
更新:现在 pandas 0.13 已经发布,另一种实现方法是df.query('line_race != 0')
。
解决方案 8:
尽管如此,给出的答案是正确的,正如上面有人说的那样,您可以df.query('line_race != 0')
根据自己的问题使用哪种方法更快。强烈推荐。
解决方案 9:
有多种方法可以实现这一点。下面将列出各种选项,供您根据用例的具体情况使用。
人们会认为OP的数据框存储在变量中df
。
选项 1
对于 OP 的情况,考虑到唯一具有值的列0
是line_race
,以下内容将完成工作
df_new = df[df != 0].dropna()
[Out]:
line_date daysago line_race rating rw wrating
0 2007-03-31 62 11.0 56 1.000000 56.000000
1 2007-03-10 83 11.0 67 1.000000 67.000000
2 2007-02-10 111 9.0 66 1.000000 66.000000
3 2007-01-13 139 10.0 83 0.880678 73.096278
4 2006-12-23 160 10.0 88 0.793033 69.786942
5 2006-11-09 204 9.0 52 0.636655 33.106077
6 2006-10-22 222 8.0 66 0.581946 38.408408
7 2006-09-29 245 9.0 70 0.518825 36.317752
8 2006-09-16 258 11.0 68 0.486226 33.063381
9 2006-08-30 275 8.0 72 0.446667 32.160051
10 2006-02-11 475 5.0 65 0.164591 10.698423
然而,由于情况并非总是如此,因此建议检查以下选项,其中指定列名。
选项 2
tshauck 的方法最终比选项 1 更好,因为可以指定列。但是,根据引用列的方式,还有其他变化:
例如,使用数据框中的位置
df_new = df[df[df.columns[2]] != 0]
或者通过如下方式明确指示列
df_new = df[df['line_race'] != 0]
也可以使用相同的登录名,但使用自定义 lambda 函数,例如
df_new = df[df.apply(lambda x: x['line_race'] != 0, axis=1)]
[Out]:
line_date daysago line_race rating rw wrating
0 2007-03-31 62 11.0 56 1.000000 56.000000
1 2007-03-10 83 11.0 67 1.000000 67.000000
2 2007-02-10 111 9.0 66 1.000000 66.000000
3 2007-01-13 139 10.0 83 0.880678 73.096278
4 2006-12-23 160 10.0 88 0.793033 69.786942
5 2006-11-09 204 9.0 52 0.636655 33.106077
6 2006-10-22 222 8.0 66 0.581946 38.408408
7 2006-09-29 245 9.0 70 0.518825 36.317752
8 2006-09-16 258 11.0 68 0.486226 33.063381
9 2006-08-30 275 8.0 72 0.446667 32.160051
10 2006-02-11 475 5.0 65 0.164591 10.698423
选项 3
使用pandas.Series.map
自定义 lambda 函数
df_new = df['line_race'].map(lambda x: x != 0)
[Out]:
line_date daysago line_race rating rw wrating
0 2007-03-31 62 11.0 56 1.000000 56.000000
1 2007-03-10 83 11.0 67 1.000000 67.000000
2 2007-02-10 111 9.0 66 1.000000 66.000000
3 2007-01-13 139 10.0 83 0.880678 73.096278
4 2006-12-23 160 10.0 88 0.793033 69.786942
5 2006-11-09 204 9.0 52 0.636655 33.106077
6 2006-10-22 222 8.0 66 0.581946 38.408408
7 2006-09-29 245 9.0 70 0.518825 36.317752
8 2006-09-16 258 11.0 68 0.486226 33.063381
9 2006-08-30 275 8.0 72 0.446667 32.160051
10 2006-02-11 475 5.0 65 0.164591 10.698423
选项 4
使用pandas.DataFrame.drop
如下
df_new = df.drop(df[df['line_race'] == 0].index)
[Out]:
line_date daysago line_race rating rw wrating
0 2007-03-31 62 11.0 56 1.000000 56.000000
1 2007-03-10 83 11.0 67 1.000000 67.000000
2 2007-02-10 111 9.0 66 1.000000 66.000000
3 2007-01-13 139 10.0 83 0.880678 73.096278
4 2006-12-23 160 10.0 88 0.793033 69.786942
5 2006-11-09 204 9.0 52 0.636655 33.106077
6 2006-10-22 222 8.0 66 0.581946 38.408408
7 2006-09-29 245 9.0 70 0.518825 36.317752
8 2006-09-16 258 11.0 68 0.486226 33.063381
9 2006-08-30 275 8.0 72 0.446667 32.160051
10 2006-02-11 475 5.0 65 0.164591 10.698423
选项 5
使用pandas.DataFrame.query
如下
df_new = df.query('line_race != 0')
[Out]:
line_date daysago line_race rating rw wrating
0 2007-03-31 62 11.0 56 1.000000 56.000000
1 2007-03-10 83 11.0 67 1.000000 67.000000
2 2007-02-10 111 9.0 66 1.000000 66.000000
3 2007-01-13 139 10.0 83 0.880678 73.096278
4 2006-12-23 160 10.0 88 0.793033 69.786942
5 2006-11-09 204 9.0 52 0.636655 33.106077
6 2006-10-22 222 8.0 66 0.581946 38.408408
7 2006-09-29 245 9.0 70 0.518825 36.317752
8 2006-09-16 258 11.0 68 0.486226 33.063381
9 2006-08-30 275 8.0 72 0.446667 32.160051
10 2006-02-11 475 5.0 65 0.164591 10.698423
选项 6
使用pandas.DataFrame.drop
andpandas.DataFrame.query
如下
df_new = df.drop(df.query('line_race == 0').index)
[Out]:
line_date daysago line_race rating rw wrating
0 2007-03-31 62 11.0 56 1.000000 56.000000
1 2007-03-10 83 11.0 67 1.000000 67.000000
2 2007-02-10 111 9.0 66 1.000000 66.000000
3 2007-01-13 139 10.0 83 0.880678 73.096278
4 2006-12-23 160 10.0 88 0.793033 69.786942
5 2006-11-09 204 9.0 52 0.636655 33.106077
6 2006-10-22 222 8.0 66 0.581946 38.408408
7 2006-09-29 245 9.0 70 0.518825 36.317752
8 2006-09-16 258 11.0 68 0.486226 33.063381
9 2006-08-30 275 8.0 72 0.446667 32.160051
10 2006-02-11 475 5.0 65 0.164591 10.698423
选项 7
如果对输出没有强烈的意见,可以使用矢量化方法numpy.select
df_new = np.select([df != 0], [df], default=np.nan)
[Out]:
[['2007-03-31' 62 11.0 56 1.0 56.0]
['2007-03-10' 83 11.0 67 1.0 67.0]
['2007-02-10' 111 9.0 66 1.0 66.0]
['2007-01-13' 139 10.0 83 0.880678 73.096278]
['2006-12-23' 160 10.0 88 0.793033 69.786942]
['2006-11-09' 204 9.0 52 0.636655 33.106077]
['2006-10-22' 222 8.0 66 0.581946 38.408408]
['2006-09-29' 245 9.0 70 0.518825 36.317752]
['2006-09-16' 258 11.0 68 0.486226 33.063381]
['2006-08-30' 275 8.0 72 0.446667 32.160051]
['2006-02-11' 475 5.0 65 0.164591 10.698423]]
这也可以使用以下方式转换为数据框:
df_new = pd.DataFrame(df_new, columns=df.columns)
[Out]:
line_date daysago line_race rating rw wrating
0 2007-03-31 62 11.0 56 1.0 56.0
1 2007-03-10 83 11.0 67 1.0 67.0
2 2007-02-10 111 9.0 66 1.0 66.0
3 2007-01-13 139 10.0 83 0.880678 73.096278
4 2006-12-23 160 10.0 88 0.793033 69.786942
5 2006-11-09 204 9.0 52 0.636655 33.106077
6 2006-10-22 222 8.0 66 0.581946 38.408408
7 2006-09-29 245 9.0 70 0.518825 36.317752
8 2006-09-16 258 11.0 68 0.486226 33.063381
9 2006-08-30 275 8.0 72 0.446667 32.160051
10 2006-02-11 475 5.0 65 0.164591 10.698423
至于最有效的解决方案,这取决于人们如何衡量效率。假设人们想要测量执行时间,一种方法是使用time.perf_counter()
。
如果测量上述所有选项的执行时间,可以得到以下结果
method time
0 Option 1 0.00000110000837594271
1 Option 2.1 0.00000139995245262980
2 Option 2.2 0.00000369996996596456
3 Option 2.3 0.00000160001218318939
4 Option 3 0.00000110000837594271
5 Option 4 0.00000120000913739204
6 Option 5 0.00000140001066029072
7 Option 6 0.00000159995397552848
8 Option 7 0.00000150001142174006
但是,这可能会根据所使用的数据框、要求(例如硬件)等而改变。
笔记:
关于使用有各种建议
inplace=True
。建议阅读此文:https ://stackoverflow.com/a/59242208/7109869还有一些人对此有强烈的意见
.apply()
。建议阅读此文:我什么时候应该(不)想在代码中使用 pandas apply()?如果有缺失值,可能还需要考虑
pandas.DataFrame.dropna
。使用选项 2,它将类似于
df = df[df['line_race'] != 0].dropna()
还有其他方法可以测量执行时间,因此我推荐这个线程: 如何获取 Python 程序执行的时间?
解决方案 10:
其中一种有效且流行的方法是使用eq()
方法:
df[~df.line_race.eq(0)]
解决方案 11:
另一种方法。可能不是最有效的方法,因为代码看起来比其他答案中提到的代码更复杂一些,但仍然是做同样事情的另一种方法。
df = df.drop(df[df['line_race']==0].index)
解决方案 12:
我编译并运行了我的代码。这是准确的代码。你可以自己尝试一下。
data = pd.read_excel('file.xlsx')
''
如果列名中有任何特殊字符或空格,您可以像给定的代码中那样写入:
data = data[data['expire/t'].notnull()]
print (date)
如果只有一个字符串列名,没有任何空格或特殊字符,则可以直接访问它。
data = data[data.expire ! = 0]
print (date)
解决方案 13:
提供了这么多选项(或者也许我没有太注意,如果是这种情况,很抱歉),但没有人提到这一点:我们可以在 pandas 中使用这种符号:〜(这给了我们条件的逆)
df = df[~df["line_race"] == 0]
解决方案 14:
只需添加另一种方法即可扩展所有列的 DataFrame:
for column in df.columns:
df = df[df[column]!=0]
例子:
def z_score(data,count):
threshold=3
for column in data.columns:
mean = np.mean(data[column])
std = np.std(data[column])
for i in data[column]:
zscore = (i-mean)/std
if(np.abs(zscore)>threshold):
count=count+1
data = data[data[column]!=i]
return data,count
解决方案 15:
以防万一您需要删除行,但值可能位于不同的列中。在我的例子中,我使用的是百分比,所以我想删除任何列中值为 1 的行,因为这意味着它是 100%
for x in df:
df.drop(df.loc[df[x]==1].index, inplace=True)
如果你的 df 有太多列,则不是最佳选择。
解决方案 16:
您可以尝试使用这个:
df.drop(df[df.line_race != 0].index, inplace = True)
。
解决方案 17:
如果需要根据索引值删除行,则顶部答案中的布尔索引也可以调整。例如,在下面的代码中,索引在 3 到 7 之间的行将被删除。
df = pd.DataFrame({'A': range(10), 'B': range(50,60)})
x = df[(df.index < 3) | (df.index > 7)]
# or equivalently
y = df[~((df.index >= 3) & (df.index <= 7))]
# or using query
z = df.query("~(3 <= index <= 7)")
# if the index has a name (as in the OP), use the name
# to select rows in 2007:
df.query("line_date.dt.year == 2007")
正如其他人提到的,query()
这是一个非常易读的函数,非常适合这项任务。事实上,对于大型数据帧,它是完成这项任务的最快方法(请参阅此答案以了解基准测试结果)。
一些常见问题query()
:
对于带有空格的列名,请使用反引号。
df = pd.DataFrame({'col A': [0, 1, 2, 0], 'col B': ['a', 'b', 'cd', 'e']})
# wrap a column name with space by backticks
x = df.query('`col A` != 0')
要引用本地环境中的变量,请在其前面加上
@
。
to_exclude = [0, 2]
y = df.query('`col A` != @to_exclude')
也可以调用系列方法。
# remove rows where the length of the string in column B is not 1
z = df.query("`col B`.str.len() == 1")
解决方案 18:
对于像这样的简单示例,这并没有太大区别,但对于复杂的逻辑,我更喜欢drop()
在删除行时使用,因为它比使用逆逻辑更直接。例如,删除行A=1 AND (B=2 OR C=3)
。
这是一个易于理解且可以处理复杂逻辑的可扩展语法:
df.drop( df.query(" `line_race` == 0 ").index)
解决方案 19:
此主题中有几个答案涉及索引,如果索引有重复项,大多数答案都将不起作用。是的,上面的至少一条评论已经指出了这一点,并且还指出重新索引是解决此问题的一种方法。下面是一个带有重复索引的示例来说明该问题。
df = pd.DataFrame(data=[(1,'A'), (0,'B'), (1,'C')], index=[1,2,2],
columns=['line_race','C2'])
print("Original with a duplicate index entry:")
print(df)
df = pd.DataFrame(data=[(1,'A'), (0,'B'), (1,'C')], index=[1,2,2],
columns=['line_race','C2'])
df.drop(df[df.line_race == 0].index, inplace = True)
print("
Incorrect rows removed:")
print(df)
df = pd.DataFrame(data=[(1,'A'), (0,'B'), (1,'C')], index=[1,2,2],
columns=['line_race','C2'])
df.reset_index(drop=False, inplace=True)
df.drop(df[df.line_race == 0].index, inplace = True)
df.set_index('index', drop=True, inplace=True)
df.index.name = None
print("
Correct row removed:")
print(df)
这是输出:
Original with a duplicate index entry:
line_race C2
1 1 A
2 0 B
2 1 C
Incorrect rows removed:
line_race C2
1 1 A
Correct row removed:
line_race C2
1 1 A
2 1 C
解决方案 20:
使用.loc
而不使用.drop
,您可以使用:
df = df.loc[df['line_race']!=0]