У меня есть кадр данных StructField со смешанной схемой (DoubleType, StringType, LongType и т. д.).
Я хочу "перебрать" все столбцы, чтобы вернуть сводную статистику. Например:
set_min = df.select([
fn.min(self.df[c]).alias(c) for c in self.df.columns
]).collect()
Это то, что я использую, чтобы найти минимальное значение в каждом столбце. Это прекрасно работает. Но когда я пытаюсь найти что-то подобное, чтобы найти Nulls:
set_null = df.filter(
(lambda x: self.df[x]).isNull().count()
).collect()
Я получаю TypeError: condition should be string or Column, что имеет смысл, я передаю функцию.
или с пониманием списка:
set_null = self.df[c].alias(c).isNull() for c in self.df.columns
Затем я пытаюсь передать ему SQL-запрос в виде строки:
set_null = df.filter('SELECT fields FROM table WHERE column = NUL').collect()
Я получил:
ParseException: "\nmismatched input 'FROM' expecting <EOF>(line 1, pos 14)\n\n== SQL ==\nSELECT fields FROM table WHERE column = NULL\n--------------^^^\n"
Как я могу передать свою функцию как "строку или столбец", чтобы я мог использовать filter или where в качестве альтернативы, почему чистый оператор SQL не работает?
Ответ 1 · рейтинг 2 · sgvd
В некоторых частях ваших попыток есть ошибки:
- Вам не хватает квадратных скобок в вашем примере понимания списка
- Вы пропустили L в
NUL
- Ваш чистый SQL не работает, потому что
filter/where ожидает предложение where, а не полный оператор SQL; это просто псевдонимы, и я предпочитаю использовать where, чтобы было понятнее, вам просто нужно указать такой пункт
В конце концов, вам не нужно использовать where, как показывает Карлсон. Но вычитание из общего количества означает, что вам нужно дважды оценить фрейм данных (что можно облегчить с помощью кэширования, но все же не идеально). Есть более прямой способ:
>>> df.select([fn.sum(fn.isnull(c).cast('int')).alias(c) for c in df.columns]).show()
+---+---+
| A| B|
+---+---+
| 2| 3|
+---+---+
Это работает, потому что приведение логического значения к целому числу дает 1 вместо True и 0 вместо False. Если вы предпочитаете SQL, эквивалент:
df.select([fn.expr('SUM(CAST(({c} IS NULL) AS INT)) AS {c}'.format(c=c)) for c in df.columns]).show()
или лучше, без приведения:
df.select([fn.expr('SUM(IF({c} IS NULL, 1, 0)) AS {c}'.format(c=c)) for c in df.columns]).show()
Ответ 2 · karlson
Если вы хотите подсчитать NULL значений в столбце, вы можете подсчитать ненулевые значения и вычесть их из общего количества.
Например:
from pyspark.sql import SparkSession
from pyspark.sql import functions as fn
spark = SparkSession.builder.master("local").getOrCreate()
df = spark.createDataFrame(
data=[
(1, None),
(1, 1),
(None, None),
(1, 1),
(None, 1),
(1, None),
],
schema=("A", "B")
)
total = df.count()
missing_counts = df.select(
*[(total - fn.count(col)).alias("missing(%s)" % col) for col in df.columns]
)
missing_counts.show()
>>> +----------+----------+
... |missing(A)|missing(B)|
... +----------+----------+
... | 2| 3|
... +----------+----------+