Python Pyspark检查是否有任何行大于零
我想过滤掉列表中所有列的零值行 假设我们有下面的dfPython Pyspark检查是否有任何行大于零,python,dataframe,apache-spark,pyspark,apache-spark-sql,Python,Dataframe,Apache Spark,Pyspark,Apache Spark Sql,我想过滤掉列表中所有列的零值行 假设我们有下面的df df = spark.createDataFrame([(0, 1, 1, 2,1), (0, 0, 1, 0, 1), (1, 0, 1, 1 ,1)], ['a', 'b', 'c', 'd', 'e']) +---+---+---+---+---+ | a| b| c| d| e| +---+---+---+-
df = spark.createDataFrame([(0, 1, 1, 2,1), (0, 0, 1, 0, 1), (1, 0, 1, 1 ,1)], ['a', 'b', 'c', 'd', 'e'])
+---+---+---+---+---+
| a| b| c| d| e|
+---+---+---+---+---+
| 0| 1| 1| 2| 1|
| 0| 0| 1| 0| 1|
| 1| 0| 1| 1| 1|
+---+---+---+---+---+
列的列表是['a','b','d',,所以过滤后的数据帧应该是
+---+---+---+---+---+
| a| b| c| d| e|
+---+---+---+---+---+
| 0| 1| 1| 2| 1|
| 1| 0| 1| 1| 1|
+---+---+---+---+---+
这就是我尝试过的
df = df.withColumn('total', sum(df[col] for col in ['a', 'b', 'd']))
df = df.filter(df.total > 0).drop('total')
这对于小数据集很好,但如果列列表很长,并且出现以下错误,则会失败,并出现以下错误
ava.lang.StackOverflowErrorat org.apache.spark.sql.catalyst.analysis.resolvellambdavariables.org$apache$spark$sql$catalyst$analysis$resolvellambdavariables$$resolvelvehigher
我可以想到熊猫udf解决方案,但我的df非常大,这可能是一个瓶颈
编辑:
当使用@Psidom的答案时,我得到以下错误
py4j.protocol.Py4JJavaError:调用o2508.filter时出错。
:java.lang.StackOverflower错误
位于org.apache.spark.sql.catalyst.expressions.Expression.referencesExpression.scala:88
在org.apache.spark.sql.catalyst.expressions.Expression$$anonfun$引用$1.applyExpression.scala:88
在org.apache.spark.sql.catalyst.expressions.Expression$$anonfun$引用$1.applyExpression.scala:88
在scala.collection.TraversableLike$$anonfun$flatMap$1.applyTraversableLike.scala:241
在scala.collection.TraversableLike$$anonfun$flatMap$1.applyTraversableLike.scala:241
位于scala.collection.immutable.List.foreachList.scala:392
在scala.collection.TraversableLike$class.flatMapTraversableLike.scala:241
位于scala.collection.immutable.List.flatMapList.scala:355
在这里可能有用:
df = spark.createDataFrame([(0, 1, 1, 2,1), (0, 0, 1, 0, 1), (1, 0, 1, 1 ,1)],
['a', 'b', 'c', 'd', 'e'])
cols = ['a', 'b', 'd']
使用reduce创建过滤器表达式:
from functools import reduce
predicate = reduce(lambda a, b: a | b, [df[x] != 0 for x in cols])
print(predicate)
# Column<b'(((NOT (a = 0)) OR (NOT (b = 0))) OR (NOT (d = 0)))'>
在这里可能有用:
df = spark.createDataFrame([(0, 1, 1, 2,1), (0, 0, 1, 0, 1), (1, 0, 1, 1 ,1)],
['a', 'b', 'c', 'd', 'e'])
cols = ['a', 'b', 'd']
使用reduce创建过滤器表达式:
from functools import reduce
predicate = reduce(lambda a, b: a | b, [df[x] != 0 for x in cols])
print(predicate)
# Column<b'(((NOT (a = 0)) OR (NOT (b = 0))) OR (NOT (d = 0)))'>
这里有一个不同的解决方案。还没有尝试过大的列集,请让我知道这是否有效
df = spark.createDataFrame([(0, 1, 1, 2,1), (0, 0, 1, 0, 1), (1, 0, 1, 1 ,1)], ['a', 'b', 'c', 'd', 'e'])
df.show()
+---+---+---+---+---+
| a| b| c| d| e|
+---+---+---+---+---+
| 0| 1| 1| 2| 1|
| 0| 0| 1| 0| 1|
| 1| 0| 1| 1| 1|
+---+---+---+---+---+
df = df.withColumn("Concat_cols" , F.concat(*list_of_cols)) # concat the list of columns
df.show()
+---+---+---+---+---+-----------+
| a| b| c| d| e|Concat_cols|
+---+---+---+---+---+-----------+
| 0| 1| 1| 2| 1| 012|
| 0| 0| 1| 0| 1| 000|
| 1| 0| 1| 1| 1| 101|
+---+---+---+---+---+-----------+
pattern = '0' * len(list_of_cols)
df1 = df.where(df['Concat_cols'] != pattern) # pattern will be 0's and the number will be equal to length of the columns list.
df1.show()
+---+---+---+---+---+-----------+
| a| b| c| d| e|Concat_cols|
+---+---+---+---+---+-----------+
| 0| 1| 1| 2| 1| 012|
| 1| 0| 1| 1| 1| 101|
+---+---+---+---+---+-----------+
这里有一个不同的解决方案。还没有尝试过大的列集,请让我知道这是否有效
df = spark.createDataFrame([(0, 1, 1, 2,1), (0, 0, 1, 0, 1), (1, 0, 1, 1 ,1)], ['a', 'b', 'c', 'd', 'e'])
df.show()
+---+---+---+---+---+
| a| b| c| d| e|
+---+---+---+---+---+
| 0| 1| 1| 2| 1|
| 0| 0| 1| 0| 1|
| 1| 0| 1| 1| 1|
+---+---+---+---+---+
df = df.withColumn("Concat_cols" , F.concat(*list_of_cols)) # concat the list of columns
df.show()
+---+---+---+---+---+-----------+
| a| b| c| d| e|Concat_cols|
+---+---+---+---+---+-----------+
| 0| 1| 1| 2| 1| 012|
| 0| 0| 1| 0| 1| 000|
| 1| 0| 1| 1| 1| 101|
+---+---+---+---+---+-----------+
pattern = '0' * len(list_of_cols)
df1 = df.where(df['Concat_cols'] != pattern) # pattern will be 0's and the number will be equal to length of the columns list.
df1.show()
+---+---+---+---+---+-----------+
| a| b| c| d| e|Concat_cols|
+---+---+---+---+---+-----------+
| 0| 1| 1| 2| 1| 012|
| 1| 0| 1| 1| 1| 101|
+---+---+---+---+---+-----------+
如果目的只是检查所有列中出现的0,并且列表导致了问题,那么可能一次将它们合并1000次,然后测试是否出现非零 从pyspark.sql导入函数为F 要测试的所有列或任何列。 columns=df.columns 一次需要连接的列。 拆分=1000 连接到单个列中的1000列的列表 块=[F.concat*列[i*split:i+1*split] 对于rangelencolumns+split-1//split]中的i 此处的表达式替换零以检查结果字符串是否为空。 选择* .whereF.regexp_replaceF.concat*blocks.aliasconcat,0,!= .show10,错
如果目的只是检查所有列中出现的0,并且列表导致了问题,那么可能一次将它们合并1000次,然后测试是否出现非零 从pyspark.sql导入函数为F 要测试的所有列或任何列。 columns=df.columns 一次需要连接的列。 拆分=1000 连接到单个列中的1000列的列表 块=[F.concat*列[i*split:i+1*split] 对于rangelencolumns+split-1//split]中的i 此处的表达式替换零以检查结果字符串是否为空。 选择* .whereF.regexp_replaceF.concat*blocks.aliasconcat,0,!= .show10,错
可以将列作为数组传递给UDF,然后检查所有值是否为零,然后应用过滤器:
from pyspark.sql.types import BooleanType
from pyspark.sql.functions import udf, array, col
all_zeros_udf = udf(lambda arr: arr.count(0) == len(arr), BooleanType())
df = spark.createDataFrame([(0, 1, 1, 2,1), (0, 0, 1, 0, 1), (1, 0, 1, 1 ,1)], ['a', 'b', 'c', 'd', 'e'])
df
.withColumn('all_zeros', all_zeros_udf(array('a', 'b', 'd'))) # pass the columns as array
.filter(~col('all_zeros')) # Filter the columns where all values are NOT zeros
.drop('all_zeros') # Drop the column
.show()
结果:
+---+---+---+---+---+
| a| b| c| d| e|
+---+---+---+---+---+
| 0| 1| 1| 2| 1|
| 1| 0| 1| 1| 1|
+---+---+---+---+---+
可以将列作为数组传递给UDF,然后检查所有值是否为零,然后应用过滤器:
from pyspark.sql.types import BooleanType
from pyspark.sql.functions import udf, array, col
all_zeros_udf = udf(lambda arr: arr.count(0) == len(arr), BooleanType())
df = spark.createDataFrame([(0, 1, 1, 2,1), (0, 0, 1, 0, 1), (1, 0, 1, 1 ,1)], ['a', 'b', 'c', 'd', 'e'])
df
.withColumn('all_zeros', all_zeros_udf(array('a', 'b', 'd'))) # pass the columns as array
.filter(~col('all_zeros')) # Filter the columns where all values are NOT zeros
.drop('all_zeros') # Drop the column
.show()
结果:
+---+---+---+---+---+
| a| b| c| d| e|
+---+---+---+---+---+
| 0| 1| 1| 2| 1|
| 1| 0| 1| 1| 1|
+---+---+---+---+---+
这只适用于列数较少的情况,在我的情况下,列数以千为单位,我得到一个错误,错误日志添加到问题中。这只适用于列数较少的情况,在我的情况下,列数以千为单位,我得到一个错误,问题中添加了错误日志,但不确定将如此长的字符串存储在具有数百万行的df中是否是一个好主意。我认为性能方面的UDF会更好。如果您不想使用这些字符串数据创建新的数据帧,那么您可以将这两个字符串组合成一行代码。df1=df.其中f.concat*列模式工作起来很有魅力,但不确定在具有数百万行的df中存储如此长的字符串是否是一个好主意。我认为性能方面的UDF会更好。如果您不想使用这些字符串数据创建新的数据帧,那么您可以将这两个数据帧组合成一行代码。df1=df.其中f.concat*列谢谢,当我们有数百万行和数千列时,你认为使用udf是一个好主意吗?这取决于你如何使用它。我们每天使用许多自定义项来处理TB的数据。谢谢,当我们有数百万行和数千列时,您认为使用自定义项是一个好主意吗?视情况而定 关于你如何使用它。我们每天使用许多UDF来处理TB的数据。