Как удалить столбцы, а не строки, используя эквивалент оси pandas в pyspark?

У меня есть фрейм данных искры, как показано ниже

df = pd.DataFrame({
'subject_id':[1,1,1,1,2,2,2,2,3,3,4,4,4,4,4],
'readings' : ['READ_1','READ_2','READ_1','READ_3',np.nan,'READ_5',np.nan,'READ_8','READ_10','READ_12','READ_11','READ_14','READ_09','READ_08','READ_07'],
 'val' :[5,np.nan,7,np.nan,np.nan,7,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,46],
 })

from pyspark.sql.types import *
from pyspark.sql.functions import isnan, when, count, col

mySchema = StructType([ StructField("subject_id", LongType(), True)\
                       ,StructField("readings", StringType(), True)\
                       ,StructField("val", FloatType(), True)])

spark_df = spark.createDataFrame(df,schema=mySchema)

Что я хотел бы сделать, так это удалить столбцы, в которых более 80% значений NaN, NULL or 0?

Я пробовал что-то вроде ниже, но это не работает

spark_df = spark_df.dropna(axis = 'columns',how=any,thresh=12)

Вышеупомянутое возможно в pandas, но здесь это не работает. Я получаю следующую ошибку, и это не удивительно

TypeError: dropna() получила неожиданный аргумент ключевого слова «ось»

Обратите внимание, что мой реальный фрейм данных 40 million and 3k columns. Я сослался на этот пост но на него пока нет ответа

Есть ли что-нибудь эквивалентное этому в pyspark?

Я ожидаю, что мой вывод будет таким, как показано ниже, всего с двумя столбцами.

введите здесь описание изображения


person The Great    schedule 29.10.2019    source источник


Ответы (2)


Вы можете использовать параметр subset в методе dropna, чтобы указать столбцы, в которых нужно искать нулевые значения.

Чтобы удалить все столбцы с нулевыми значениями более 80%:

columns_to_drop = []
count_before = spark_df.count()

for column_name in spark_df.columns:
    temp_spark_df =  spark_df.dropna(subset=[column_name], how=any, thresh=12)
    count_after = temp_spark_df.count()

    if ((count_before-count_after)/count_before) > 0.8:
        columns_to_drop.append(column_name)


spark_df = spark_df.drop(*columns_to_drop)

person Rithin Chalumuri    schedule 29.10.2019
comment
Спасибо попробую. Но, к сожалению, мой фрейм данных действительно огромен, до 40 миллионов и 3 тыс. столбцов. Вот и думаю будет ли быстро. В любом случае проголосовал. Постараюсь обновить ответ в ближайшее время. Спасибо - person The Great; 29.10.2019

Вы можете напрямую использовать эту функцию, она самая быстрая:

def drop_null_columns_spark(df, threshold=0):
    """
    This function drops all columns which contain null values with a threshold.
    :param df: A PySpark DataFrame
    :param threshold: Minimum number of nulls to consider dropping of column
    """
    null_counts = df.select([F.count(F.when(F.col(c).isNull(), c)).alias(c) for c in df.columns]).collect()[0].asDict()
    to_drop = [k for k, v in null_counts.items() if v > threshold]
    df = df.drop(*to_drop)
    return df
person pissall    schedule 31.10.2019
comment
Спасибо попробую. Проголосовал. Но я уже пробовал подобный подход. Разве это не займет больше времени, например, для 1300 столбцов? - person The Great; 09.11.2019
comment
@SSMK Count — это дорогостоящая операция, но она необходима, потому что вам нужно право нулевого подсчета. Сбор недорогой, потому что вы объединились в одну строку. - person pissall; 09.11.2019