স্পার্ক ডেটা ফ্রেম কলামটি অজগর তালিকায় রূপান্তর করুন


107

আমি দুটি কলাম, এমভিভি এবং গণনা সহ একটি ডেটাফ্রেমে কাজ করি।

+---+-----+
|mvv|count|
+---+-----+
| 1 |  5  |
| 2 |  9  |
| 3 |  3  |
| 4 |  1  |

আমি এমভিভি মান এবং গণনা মান সমন্বিত দুটি তালিকা পেতে চাই। কিছুটা এইরকম

mvv = [1,2,3,4]
count = [5,9,3,1]

সুতরাং, আমি নিম্নলিখিত কোডটি চেষ্টা করেছিলাম: প্রথম লাইনে সারিটির একটি অজগর তালিকাটি ফিরিয়ে দেওয়া উচিত। আমি প্রথম মানটি দেখতে চেয়েছিলাম:

mvv_list = mvv_count_df.select('mvv').collect()
firstvalue = mvv_list[0].getInt(0)

তবে আমি দ্বিতীয় লাইনের সাথে একটি ত্রুটি বার্তা পেয়েছি:

অ্যাট্রিবিউটআরার: getInt


স্পার্ক 2.3 এর হিসাবে, এই কোড দ্রুততম এবং অন্তত সম্ভবত OutOfMemory ব্যতিক্রম কারণ: list(df.select('mvv').toPandas()['mvv'])তীরটি পাইস্পার্কে সংহত হয়েছিল যা toPandasউল্লেখযোগ্যভাবে বৃদ্ধি পেয়েছিল । আপনি যদি স্পার্ক ২.৩+ ব্যবহার করেন তবে অন্যান্য পদ্ধতিগুলি ব্যবহার করবেন না। আরও বেঞ্চমার্কিং বিশদ জন্য আমার উত্তর দেখুন।
শক্তি

উত্তর:


147

দেখুন, আপনি কেন এইভাবে করছেন তা কাজ করছে না। প্রথমত, আপনি একটি সারি টাইপ থেকে পূর্ণসংখ্যার চেষ্টা করছেন , আপনার সংগ্রহের আউটপুটটি এরকম:

>>> mvv_list = mvv_count_df.select('mvv').collect()
>>> mvv_list[0]
Out: Row(mvv=1)

আপনি যদি এই জাতীয় কিছু গ্রহণ করেন:

>>> firstvalue = mvv_list[0].mvv
Out: 1

আপনি mvvমান পাবেন। আপনি যদি অ্যারের সমস্ত তথ্য চান তবে আপনি এই জাতীয় কিছু নিতে পারেন:

>>> mvv_array = [int(row.mvv) for row in mvv_list.collect()]
>>> mvv_array
Out: [1,2,3,4]

তবে আপনি যদি অন্য কলামের জন্য একই চেষ্টা করেন তবে আপনি পাবেন:

>>> mvv_count = [int(row.count) for row in mvv_list.collect()]
Out: TypeError: int() argument must be a string or a number, not 'builtin_function_or_method'

এটি countঅন্তর্নির্মিত পদ্ধতি হওয়ায় এটি ঘটে । এবং কলামটির একই নাম রয়েছে count। এই কাজ করতে একটি কার্যসংক্রান্ত কলাম নাম পরিবর্তন হয় countথেকে _count:

>>> mvv_list = mvv_list.selectExpr("mvv as mvv", "count as _count")
>>> mvv_count = [int(row._count) for row in mvv_list.collect()]

অভিধানের বাক্য গঠনটি ব্যবহার করে আপনি কলামটি অ্যাক্সেস করতে পারেন, তবে এই কাজের দরকার নেই:

>>> mvv_array = [int(row['mvv']) for row in mvv_list.collect()]
>>> mvv_count = [int(row['count']) for row in mvv_list.collect()]

এবং অবশেষে এটি কাজ করবে!


এটি প্রথম কলামের জন্য দুর্দান্ত কাজ করে, তবে এটি (স্পার্কের ফাংশন গণনা) কারণে আমি মনে করি কলাম গণনার পক্ষে কাজ করে না
a.moussa

আপনি গণনা দিয়ে কী করছেন তা যুক্ত করতে পারেন? মন্তব্য এখানে যুক্ত করুন।
থিয়াগো বালদিম

আপনার প্রতিক্রিয়ার জন্য ধন্যবাদ তাই এই লাইনটি এমভিভি_লিস্ট = [ইনট্রে (আই.এমভিভি) এমভিভি_কাউন্ট.সलेक्ट করুন ('এমভিভি') এ সংগ্রহ করুন (সংগ্রহ করুন)) তবে এই এমভিভি_কাউন্টে আমার জন্য একটি গণনা তালিকা = [ইন (আই.কাউন্ট) নয় collect .সलेक्ट করুন ('গণনা')। সংগ্রহ ()] অবৈধ বাক্যবিন্যাস
ফেরান

এই select('count')ব্যবহারটি এভাবে যুক্ত করার দরকার নেই : count_list = [int(i.count) for i in mvv_list.collect()]আমি প্রতিক্রিয়াতে উদাহরণটি যুক্ত করব।
থিয়াগো বালদিম

4
@ a.moussa [i.['count'] for i in mvv_list.collect()]এটি 'গণনা' নামক কলামটি নয় এবং countফাংশনটি ব্যবহার করে তা স্পষ্ট করার জন্য কাজ করে
user989762

108

একটি লাইনার অনুসরণ করে আপনি চান তালিকা দেয়।

mvv = mvv_count_df.select("mvv").rdd.flatMap(lambda x: x).collect()

4
পারফরমেন্স জ্ঞানী এই সমাধান অনেক দ্রুত আপনার সমাধান mvv_list চেয়ে = [int তোমার জন্য (i.mvv) mvv_count.select ( 'mvv') মধ্যে () সংগ্রহ করুন।] হল
চানাকা ফার্নান্দো

এটি এখন পর্যন্ত সবচেয়ে ভাল সমাধান আমি দেখেছি। ধন্যবাদ
হুই চেন

এটি কি কেবল ওপি-র প্রশ্নের জন্য কাজ করবে না ?: এমভিভি = এমভিভি_কাউন্ট_ডিএফ.সিলিট ("এমভিভি")। rdd.flatMap (তালিকা) .ক্লোকলেট ()
eemilk

22

এটি আপনাকে তালিকা হিসাবে সমস্ত উপাদান দেবে।

mvv_list = list(
    mvv_count_df.select('mvv').toPandas()['mvv']
)

4
এটি স্পার্ক ২.৩+ এর জন্য দ্রুত এবং সবচেয়ে কার্যকর সমাধান efficient আমার উত্তরে মাপদণ্ডের ফলাফলগুলি দেখুন।
শক্তি

17

নিম্নলিখিত কোড আপনাকে সাহায্য করবে

mvv_count_df.select('mvv').rdd.map(lambda row : row[0]).collect()

4
এটি গ্রহণযোগ্য উত্তর হওয়া উচিত। কারণটি হ'ল আপনি পুরো প্রক্রিয়া জুড়ে একটি স্পার্ক প্রসঙ্গে রয়েছেন এবং তারপরে আপনি স্পার্কের প্রসঙ্গটি আগে বেরিয়ে যাওয়ার বিরোধিতা হিসাবে শেষে সংগ্রহ করেন যা আপনি যা করছেন তার উপর নির্ভর করে বৃহত্তর সংগ্রহের কারণ হতে পারে।
এন্টিপোন 79

16

আমার ডেটাতে আমি এই মানদণ্ডগুলি পেয়েছি:

>>> data.select(col).rdd.flatMap(lambda x: x).collect()

0.52 সেকেন্ড

>>> [row[col] for row in data.collect()]

0.271 সেকেন্ড

>>> list(data.select(col).toPandas()[col])

0.427 সেকেন্ড

ফলাফল একই


4
আপনি যদি এর toLocalIteratorপরিবর্তে ব্যবহার করেন collectতবে আরও মেমরি দক্ষ হওয়া উচিত[row[col] for row in data.toLocalIterator()]
ওগ্লপ

টিপ দ্বারা ধন্যবাদ! @o
আন্দ্রে

6

আপনি নীচে ত্রুটি পেতে হলে:

অ্যাট্রিবিউটআরার: 'তালিকা' অবজেক্টটির কোনও 'সংগ্রহ' নেই

এই কোডটি আপনার সমস্যার সমাধান করবে:

mvv_list = mvv_count_df.select('mvv').collect()

mvv_array = [int(i.mvv) for i in mvv_list]

আমিও ত্রুটি পেয়েছি এবং এই সমাধানটি সমস্যার সমাধান করেছে। তবে কেন আমি ত্রুটি পেয়েছি? (অন্য অনেকে তা পেয়েছেন বলে মনে হয় না!)
বিকাশগ

3

আমি একটি বেঞ্চমার্কিং বিশ্লেষণ চালিয়েছি এবং list(mvv_count_df.select('mvv').toPandas()['mvv'])এটি দ্রুততম পদ্ধতি। আমি খুব অবাক।

আমি স্পার্ক 2.4.5 এর সাথে 5 নোড আই 3.এক্স্লেজার ক্লাস্টার (প্রতিটি নোডে 30.5 জিবি র‌্যাম এবং 4 কোরের ব্যবহার) ব্যবহার করে 100 হাজার / 100 মিলিয়ন সারি ডেটাसेटগুলিতে বিভিন্ন পন্থা চালিয়েছি। একক কলাম সহ 20 টি স্মাপ্প্রেড কম্প্রেস পার্কুয়েট ফাইলগুলিতে ডেটা সমানভাবে বিতরণ করা হয়েছিল।

এখানে বেঞ্চমার্কিংয়ের ফলাফল (সেকেন্ডে রানটাইম):

+-------------------------------------------------------------+---------+-------------+
|                          Code                               | 100,000 | 100,000,000 |
+-------------------------------------------------------------+---------+-------------+
| df.select("col_name").rdd.flatMap(lambda x: x).collect()    |     0.4 | 55.3        |
| list(df.select('col_name').toPandas()['col_name'])          |     0.4 | 17.5        |
| df.select('col_name').rdd.map(lambda row : row[0]).collect()|     0.9 | 69          |
| [row[0] for row in df.select('col_name').collect()]         |     1.0 | OOM         |
| [r[0] for r in mid_df.select('col_name').toLocalIterator()] |     1.2 | *           |
+-------------------------------------------------------------+---------+-------------+

* cancelled after 800 seconds

ড্রাইভার নোডে ডেটা সংগ্রহ করার সময় স্বর্ণের নিয়মগুলি অনুসরণ করুন:

  • অন্যান্য পদ্ধতির সাহায্যে সমস্যাটি সমাধান করার চেষ্টা করুন। ড্রাইভার নোডে ডেটা সংগ্রহ করা ব্যয়বহুল, স্পার্ক ক্লাস্টারের শক্তিটি ব্যবহার করে না এবং যখনই সম্ভব সম্ভব এড়ানো উচিত।
  • যথাসম্ভব কয়েকটি সারি সংগ্রহ করুন। ডেটা সংগ্রহের আগে সমষ্টি, সদৃশ, ফিল্টার এবং কলামগুলি ছাঁটাই করুন। ড্রাইভার নোডকে যতটা সম্ভব প্রেরণ করুন।

toPandas স্পার্ক ২.৩-তে উল্লেখযোগ্যভাবে উন্নতি করা হয়েছিল । আপনি যদি স্পার্ক সংস্করণটি ২.৩ এর আগে ব্যবহার করছেন তবে এটি সম্ভবত সেরা পন্থা নয়।

আরও বিশদ / বেঞ্চমার্কিং ফলাফলের জন্য এখানে দেখুন ।


2

একটি সম্ভাব্য সমাধান collect_list()থেকে ফাংশনটি ব্যবহার করা pyspark.sql.functions। এটি সমস্ত কলাম মানকে পাইস্পার্ক অ্যারেতে একত্রিত করবে যা সংগ্রহের সময় পাইথন তালিকায় রূপান্তরিত হবে:

mvv_list   = df.select(collect_list("mvv")).collect()[0][0]
count_list = df.select(collect_list("count")).collect()[0][0] 

1

প্রশ্নে ডেটাফ্রেম তৈরি করা যাক

df_test = spark.createDataFrame(
    [
        (1, 5),
        (2, 9),
        (3, 3),
        (4, 1),
    ],
    ['mvv', 'count']
)
df_test.show()

যা দেয়

+---+-----+
|mvv|count|
+---+-----+
|  1|    5|
|  2|    9|
|  3|    3|
|  4|    1|
+---+-----+

এবং তারপরে তালিকাটি পেতে rdd.flatMap (f) .collect () প্রয়োগ করুন

test_list = df_test.select("mvv").rdd.flatMap(list).collect()
print(type(test_list))
print(test_list)

যা দেয়

<type 'list'>
[1, 2, 3, 4]
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.