#apache-spark #pyspark #pyspark-dataframes
#apache-spark #pyspark
Вопрос:
Я работаю над фреймом данных pyspark, который имеет
MINFLT MAJFLT VSTEXT VSIZE RSIZE VGROW RGROW
132K 224.4M 11160K 0 224.4M 11160K 0K
134M 224.9K 12260K 0 224.4M 11160K 0K
132K 225.5M 11160K 0 224.4M 11160K 0K
и пытается получить вывод, подобный:
MINFLT MAJFLT VSTEXT VSIZE RSIZE VGROW RGROW
132000 24400000 11160000 0 224400000 11160000 0
Я попробовал следующий код:
df.Val = (df.RSIZE.replace(r'[KM] $', '', regex=True).astype(float) *
df.RSIZE.str.extract(r'[d.] ([KM] )', expand=False)
.fillna(1)
.replace(['K','M'], [10**3, 10**6]).astype(int))
Однако я получаю следующую ошибку:
TypeError Traceback (most recent call last)
<ipython-input-206-489237518a0c> in <module>
----> 1 df.Val = (df.RSIZE.replace(r'[KM] $', '', regex=True).astype(float) *
2 df.RSIZE.str.extract(r'[d.] ([KM] )', expand=False)
3 .fillna(1)
4 .replace(['K','M'], [10**3, 10**6]).astype(int))
TypeError: 'Column' object is not callable
Как я могу это исправить?
Ответ №1:
Не могли бы вы дважды проверить, хотите ли вы использовать regexp_replace или ссылаться на replace. Я не нашел замену в классе столбцов. вы могли бы использовать regex_replace, который присутствует в функциональном модуле Pyspark.
У меня есть приведенный ниже код для вашего запроса:
from pyspark import SparkContext
sc = SparkContext.getOrCreate()
from pyspark.sql import SparkSession
spark = SparkSession(sc)
from pyspark.sql import functions as sf
from pyspark.sql.window import Window
from pyspark.sql.types import *
sample_src = spark.read.csv("sample_src.txt", header=True)
# use different value for DecimalType, M and K, as per your need
converter = lambda clm, bas_vale: sf.regexp_replace(sf.col(clm),(r'[KM]'),"").cast(DecimalType(20,8)) *bas_vale
sample_src.withColumn("RSIZE", sf.when(sf.col("RSIZE").endswith("M"), converter("RSIZE", 1000000)).otherwise(converter("RSIZE",1000))).show()
Ввод:
------ ------ ------ ----- ------ ------ -----
|MINFLT|MAJFLT|VSTEXT|VSIZE| RSIZE| VGROW|RGROW|
------ ------ ------ ----- ------ ------ -----
| 132K|224.4M|11160K| 0|224.4M|11160K| 0K|
| 134M|224.9K|12260K| 0|224.4M|11160K| 0K|
| 132K|225.5M|11160K| 0|224.4M|11160K| 0K|
------ ------ ------ ----- ------ ------ -----
Вывод:
------ ------ ------ ----- ------------------ ------ -----
|MINFLT|MAJFLT|VSTEXT|VSIZE| RSIZE| VGROW|RGROW|
------ ------ ------ ----- ------------------ ------ -----
| 132K|224.4M|11160K| 0|224400000.00000000|11160K| 0K|
| 134M|224.9K|12260K| 0|224400000.00000000|11160K| 0K|
| 132K|225.5M|11160K| 0|224400000.00000000|11160K| 0K|
------ ------ ------ ----- ------------------ ------ -----
Ответ №2:
Вы можете использовать карту и выполнить некоторые манипуляции со строками, а затем выполнить окончательный расчет.
from pyspark.sql.functions import translate, coalesce, lit, substring, expr
df = spark.createDataFrame([
('132K', '224.4M', '11160K', '0', '224.4M', '11160K', '0K')
, ('134M', '224.9K', '12260K', '0', '224.4M', '11160K', '0K')
, ('132K', '225.5M', '11160K', '0', '224.4M', '11160K', '0K')
], ['MINFLT', 'MAJFLT', 'VSTEXT', 'VSIZE', 'RSIZE', 'VGROW', 'RGROW'])
# create the Map
scale_map = expr("map('K',1000, 'M',1000000, 'G', 1000000000)")
# specify column names you want to process
cols_included = {'MAJFLT', 'RSIZE'}
# define a function to do the conversion
my_convert = lambda c: (translate(c, 'KMG', '')*coalesce(scale_map[substring(c,-1,1)],lit(1))).astype('bigint').alias(c)
df_new = df.select([ my_convert(c) if c in cols_included else c for c in df.columns ])
df_new.show()
------ --------- ------ ----- --------- ------ -----
|MINFLT| MAJFLT|VSTEXT|VSIZE| RSIZE| VGROW|RGROW|
------ --------- ------ ----- --------- ------ -----
| 132K|224400000|11160K| 0|224400000|11160K| 0K|
| 134M| 224900|12260K| 0|224400000|11160K| 0K|
| 132K|225500000|11160K| 0|224400000|11160K| 0K|
------ --------- ------ ----- --------- ------ -----
Где: в функции my_convert
мы используем translate(c, ‘KMG’, «) для удаления символов K
M
и G
(вы можете сделать то же самое с regexp_replace). используйте substring(c,-1,1), чтобы получить последний символ строки и использовать его в качестве ключа для поиска соответствующего значения scale_map[..]
. используйте coalesce(.., lit(1)), чтобы установить масштаб 1
, когда такой ключ не найден scale_map
.
Комментарии:
1. В этом методе, если у меня есть какой-либо другой столбец, в котором есть строковые значения для (‘apache2′,’mission-contro’,’whoopsie’) — значения в новом фрейме данных превращаются в null, потому что dtypes является строкой
2. проверьте обновленную запись, вам нужно указать столбцы, которые вы хотите включить, а затем использовать if / else в списке-понимание.