Khi bạn cần thực hiện các thao tác trên Pandas DataFrame theo từng hàng, bạn sẽ cần dùng đến lặp hàng. Dù Pandas được tối ưu cho các phép toán vector hóa, lặp theo hàng vẫn thiết yếu khi áp dụng logic không thể vector hóa, đặc biệt trong các thao tác dữ liệu phức tạp hoặc xử lý điều kiện theo từng hàng.
Có nhiều phương pháp bạn có thể áp dụng cho một Pandas DataFrame để lặp qua các hàng.
.iterrows(): Dùng cho các thao tác đơn giản theo hàng, khi cần cả chỉ mục và dữ liệu hàng. Trả về cặp index-series, có thể chậm với dataframe lớn và không phù hợp cho tính toán nặng.
.itertuples(): Dùng như một lựa chọn nhanh hơn .iterrows(), nhất là khi bạn không cần Pandas Series. Trả về namedtuple các giá trị hàng và tiết kiệm bộ nhớ hơn .iterrows().
.apply(axis=1): Áp dụng một hàm cho từng hàng, thường dùng với đối số axis = 1. Chậm hơn các phương pháp vector hóa, nhưng thường nhanh hơn vòng lặp tường minh.
Hiểu về lặp theo hàng trong Pandas DataFrame
Mặc dù Pandas được thiết kế để hoạt động tối ưu với các phép toán theo cột, nhiều phương pháp Python hỗ trợ lặp theo hàng, đặc biệt khi làm việc với từng hàng riêng lẻ.
Cơ chế nền tảng của lặp theo hàng
Pandas làm việc với DataFrame theo định dạng cột, nhờ đó hiệu quả khi áp dụng các biến đổi đồng thời cho các cột của DataFrame.
Đây cũng là một trong các lý do vì sao các phép toán vector hóa hiệu quả trong Pandas và thường được khuyến khích thay vì lặp theo hàng, vốn có thể chậm khi làm việc với DataFrame lớn.
Dưới đây là các phương pháp lặp theo hàng chủ đạo:
.iterrows(): Trả về mỗi hàng như một bộ (index, Series).
.itertuples(): Nhanh hơn .iterrows() và trả về mỗi hàng như một namedtuple.
.items(): Không phải lặp theo hàng, mà lặp qua các cột của Pandas DataFrame, trả về nhãn cột và Series, thường dùng cho các thao tác theo cột.
Đánh đổi hiệu năng của các cách tiếp cận lặp
Dựa trên benchmark với DataFrame cỡ vừa 100.000 hàng, .itertuples() nhanh hơn .iterrows() khoảng 5–10 lần về tốc độ và hiệu quả bộ nhớ. Lý do là .itertuples() tránh tạo đối tượng Series cho từng hàng và chỉ trả về namedtuple gọn nhẹ.
Các phép toán vector hóa nhanh hơn mọi hình thức lặp vì được triển khai bằng mã C tối ưu. Chúng loại bỏ vòng lặp ở cấp Python, giảm overhead. Ví dụ, cộng hai cột bằng datacamp_rows[“A”] + datacamp_rows[“B”] nhanh hơn dùng vòng lặp for với .iterrows().
.iterrows() có footprint bộ nhớ lớn vì trả về một đối tượng Pandas Series hoàn chỉnh, và các Series này có thể gặp vấn đề không nhất quán dtype do bắt nguồn từ các cột có kiểu dữ liệu khác nhau.
Với tập dữ liệu nhỏ, khuyến nghị dùng .iterrows(), còn với tập dữ liệu lớn hơn, bạn có thể dùng .itertuples().
Khi nào và vì sao nên lặp qua các hàng của DataFrame
Bạn có thể gặp tình huống không thể áp dụng phép toán vector hóa và buộc phải quay về lặp theo hàng. Trong những tình huống như vậy, phần này sẽ giúp bạn biết khi nào nên và không nên dùng lặp theo hàng.
Các trường hợp sử dụng điển hình của lặp theo hàng
Các tình huống điển hình gồm:
Gọi API bên ngoài: Bạn có thể dùng lặp theo hàng để gọi API bên ngoài cho dữ liệu từng hàng, chẳng hạn lấy vĩ độ và kinh độ bằng API geocoding như Google Maps hoặc OpenStreetMap từ danh sách địa chỉ khách hàng.
Áp dụng logic phức tạp: Dùng lặp theo hàng khi viết logic phức tạp liên quan nhiều cột và rẽ nhánh điều kiện.
Ghi theo từng hàng vào hệ thống ngoài: Dùng lặp theo hàng khi ghi từng hàng vào hệ thống ngoài, như ghi log vào hệ thống kế thừa không hỗ trợ cập nhật theo lô theo từng hàng.
Xử lý phụ thuộc liên hàng: Dùng lặp theo hàng trong các kịch bản như tính tồn kho lũy kế, nơi mỗi hàng ghi nhận nhập/xuất phụ thuộc vào mức tồn trước đó.
Khi không nên lặp: lưu ý và phương án thay thế
Dù có các trường hợp sử dụng, bạn nên tránh lặp theo hàng trong các trường hợp sau:
Các thao tác có vẻ theo hàng nhưng có thể vector hóa.
Khi lặp chậm và tốn bộ nhớ.
Bạn có vòng lặp lồng nhau hoặc nhiều điều kiện bên trong lặp theo hàng, dễ dẫn đến chậm theo hàm mũ khi dữ liệu tăng.
Thay vì lặp, cân nhắc các phương án sau:
Dùng các phép toán vector hóa bất cứ khi nào có thể.
Tận dụng .apply() với hàm được tối ưu cho các tác vụ phức tạp nhưng vẫn có thể vector hóa phần nào.
Cân nhắc xử lý theo lô hoặc song song nếu buộc phải lặp nhưng bị ràng buộc hiệu năng.
Bạn cần tránh các sai lầm thường gặp của vòng lặp theo hàng như:
.iterrows() trả về bản sao, không phải tham chiếu tới hàng gốc; do đó sửa đổi nó không làm thay đổi DataFrame ban đầu.
Khó đọc và bảo trì hơn so với các phép toán vector hóa.
Các phương pháp phổ biến để lặp qua hàng trong Pandas
Bạn có thể triển khai lặp theo hàng trong Pandas DataFrame bằng nhiều phương pháp, tùy thuộc vào trường hợp sử dụng hoặc bản chất của DataFrame. Dưới đây là các phương pháp để lặp qua hàng của Pandas DataFrame.
Sử dụng .iterrows()
Phương thức .iterrows() bao gồm việc lặp qua từng hàng của DataFrame. Cú pháp như sau:
for index, row in datacamp_rows.iterrows():# code to process each rowĐược hỗ trợ bởi
Trong đó datacamp_rows là dataframe được lặp, index là chỉ mục hàng, và row là Pandas Series chứa dữ liệu của hàng.
Ví dụ sử dụng cơ bản:
import pandas as pd
students ={"Name":["Mary","Joseph"],"Age":[25,30]}
students = pd.DataFrame(students)for index, row in students.iterrows():print(f"Index: {index}, Name: {row['Name']}, Age: {row['Age']}")Được hỗ trợ bởi
Phương thức .iterrows() trả về một generator tạo ra chỉ mục của hàng cùng với một đối tượng Series đại diện cho hàng. Các khóa của Series này là tên cột, và giá trị là dữ liệu tương ứng ở mỗi hàng.
.itertuples() nhanh và tiết kiệm bộ nhớ hơn .iterrows(), đồng thời trả về mỗi hàng dưới dạng namedtuple, cho phép truy cập giá trị cột bằng dot notation. Cú pháp như sau:
for row in datacamp_rows.itertuples(index=True, name="Pandas"):# process each rowĐược hỗ trợ bởi
Trong đó index=True bao gồm chỉ mục DataFrame như phần tử đầu tiên của mỗi tuple, và name="Pandas" đặt tên lớp namedtuple trả về. Nếu name=None, vòng lặp for trả về tuple thông thường không thể truy cập thuộc tính.
Ví dụ thực tế cách .itertuples() hoạt động:
import pandas as pd
students={"Name":["Mary","Joseph"],"Age":[25,30]}
students = pd.DataFrame(students)for row in students.itertuples():print(f"Index: {row.Index}, Name: {row.Name}, Age: {row.age}")Được hỗ trợ bởi
Trong đó hàm áp dụng cho hàng là func, và đối số axis=1 được thiết lập.
Dưới đây là ví dụ minh họa cách áp dụng.
import pandas as pd
students = pd.DataFrame({"Name":["Mary","Joseph"],"Math":[85,90],"Science":[95,88]})# Add a new column with average score
students["Average"]= students.apply(lambda row:(row["Math"]+ row["Science"])/2, axis=1)
students.head()Được hỗ trợ bởi
Dùng phương thức .apply() khi tạo cột mới dựa trên các cột hiện có, hoặc khi áp dụng phép tính hay biến đổi tùy chỉnh.
Về lặp theo hàng, bạn có thể dùng nó để tạo logic điều kiện theo hàng như if-else. Khi đặt axis=1, hàm được truyền một Series với tên cột làm chỉ mục. Hàm này xử lý các hàng và trả về một giá trị vô hướng trong cột mới hoặc Series trong nhiều cột.
Dù .apply(axis=1) chậm hơn các phép toán vector hóa, nó nhanh và gọn hơn .iterrows().
Dùng DataFrame.index với loc/iloc để lặp thủ công
Một cách khác để lặp theo hàng là bạn dùng .loc[] hoặc .iloc[] thủ công với vòng lặp for để lặp qua một Pandas DataFrame.
Cách này hoạt động tương tự các phương thức .iterrows() hoặc .itertuples(). Ưu điểm là bạn có toàn quyền kiểm soát các hàng. Cú pháp như sau:
# positional indexingfor i inrange(len(df)):
row = df.iloc[i]# process row# label indexingfor idx in df.index:
row = df.loc[idx]# process rowĐược hỗ trợ bởi
Dưới đây là ví dụ thực tế cách triển khai.
import pandas as pd
students = pd.DataFrame({"Name":["Mary","Joseph"],"Age":[25,30]})# Using ilocfor i inrange(len(students)):print(f"Name: {students.iloc[i]['Name']}, Age: {students.iloc[i]['Age']}")# Using locfor idx in students.index:print(f"Name: {students.loc[idx,'Name']}, Age: {students.loc[idx,'Age']}")Được hỗ trợ bởi
Một trong các trường hợp sử dụng là khi bạn cần kiểm soát chính xác thứ tự hàng, hoặc khi viết logic từng bước để gỡ lỗi. Dù vậy, cách này kém hiệu quả với dataframe lớn và cũng chậm hơn các phép toán vector hóa.
Cần dùng .loc[] khi bạn cần tra cứu theo nhãn hoặc .iloc[] khi cần truy cập theo vị trí, đặc biệt với các vòng lặp theo range.
So sánh .iterrows(), .itertuples(), và .apply()
Dưới đây là bảng tóm tắt khác biệt giữa ba phương pháp.
Tính năng
iterows()
itertuples()
apply(axis=1)
Cú pháp
for idx, row in df.iterrows:
for row in df.itertuples():
df.apply(func, axis=1)
Đầu ra
(index, Series)
namedtuple
Trả về giá trị của hàm (vô hướng hoặc Series)
Tốc độ
Chậm
Nhanh nhất
Trung bình
Sử dụng bộ nhớ
Trung bình
Thấp
Trung bình
Dễ đọc
Trung bình
Cao
Cao
Trường hợp phù hợp
Dựng thử nhanh hoặc gỡ lỗi
Tập dữ liệu lớn
Suy dẫn cột
Hạn chế
Chậm
Không xử lý được logic hàng phức tạp
Chậm hơn vector hóa hoàn toàn
Phương thức .iterrows(): Phân tích chi tiết và trường hợp sử dụng
Mặc dù .iterrows() là cách trực quan để lặp qua các hàng của Pandas DataFrame, nó có những hạn chế có thể ảnh hưởng hiệu năng.
Đặc điểm triển khai và hạn chế
Lặp với .iterrows() trả về mỗi hàng của DataFrame như một bộ gồm chỉ mục hàng và một đối tượng Series chứa dữ liệu trong hàng.
Dù đơn giản, nó có nhược điểm về chuyển đổi dtype; ví dụ, có thể chuyển số nguyên thành số thực nếu Series cần chứa kiểu hỗn hợp, dễ gây lỗi tinh vi trong tính toán hoặc so sánh.
Ngoài ra, vì .iterrows() trả về Series cho mỗi hàng, dẫn tới overhead bộ nhớ, khiến hiệu năng chậm hơn so với các phép toán vector hóa.
Việc sửa dữ liệu trong vòng lặp dùng .iterrows() không được khuyến khích, vì thay đổi trên Series không tác động ngược lại dataframe.
Ứng dụng phù hợp và cách khắc phục
Bất chấp các hạn chế trên, .iterrows() vẫn hữu ích trong một số tình huống như:
Tác dụng phụ bên ngoài: Bạn có thể dùng .iterrows() cho các thao tác không thể vector hóa như gọi API, ghi file hoặc tương tác cơ sở dữ liệu theo từng hàng.
Gỡ lỗi và khám phá: Khi gỡ lỗi, đặc biệt trong phân tích dữ liệu thăm dò và bạn muốn kiểm tra từng hàng, có thể dùng .iterrows().
Để giữ tính nhất quán dtype, cân nhắc chuyển sang .itertuples(), vì nó trả về namedtuple không chuyển đổi kiểu.
Phương thức .itertuples(): Lặp tối ưu hiệu năng
.itertuples() nhanh và tiết kiệm bộ nhớ hơn .iterrows() vì trả về namedtuple. Hãy xem một số đặc điểm khiến nó vượt trội hơn .iterrows().
Triển khai kỹ thuật và ưu điểm
Một số ưu điểm của .itertuples() gồm:
Tăng hiệu năng: Thay vì tạo đối tượng Series như .iterrows() vốn tốn bộ nhớ và giảm hiệu năng, .itertuples() tránh overhead bộ nhớ và cải thiện hiệu năng bằng generator trả về namedtuple.
Tùy biến: Đối số index=False trong .itertuples() loại bỏ chỉ mục khỏi tuple, và thiết lập name= 'Custom' cho phép đặt tên lớp namedtuple tùy chỉnh, cải thiện khả năng đọc hoặc tích hợp với hệ thống khác.
Mẫu sử dụng thực tế và hạn chế
Khi dùng .itertuples(), cần lưu ý các hạn chế sau.
Ràng buộc đặt tên cột: Tên cột chứa ký tự đặc biệt hoặc khoảng trắng có thể tạo ra định danh Python không hợp lệ. Những tên này sẽ được chỉnh thành hợp lệ hoặc truy cập bằng giải nén tuple theo chỉ số.
Bất biến:Namedtuple là bất biến, nghĩa là bạn không thể sửa giá trị tại chỗ. Điều này ngụ ý mọi biến đổi cần xây dựng cấu trúc mới hoặc thu thập giá trị mong muốn vào danh sách hay dataframe khác.
Một số thực hành tốt khi dùng .itertuples():
Dùng cho thao tác chỉ đọc như trích xuất giá trị, lọc hoặc xây dựng bản ghi ngoài.
Tích lũy kết quả đã biến đổi vào cấu trúc dữ liệu mới như danh sách.
Làm sạch tên cột để tránh lỗi thuộc tính.
Các phương án thay thế lặp theo hàng: Vector hóa và hơn thế
Dù các phương pháp lặp theo hàng chủ yếu là .iterrows() và .itertuples(), pandas cung cấp các lựa chọn khác hiệu quả hơn cho xử lý dữ liệu quy mô lớn, như vector hóa, vốn tiết kiệm bộ nhớ và nhanh hơn.
Phép toán vector hóa: cách tiếp cận tối ưu
Phép toán vector hóa áp dụng thao tác trên toàn bộ mảng hoặc cột DataFrame cùng lúc, tận dụng tối ưu hóa mức thấp trong NumPy và Pandas. Cách này gọn gàng, dễ đọc và giảm mạnh thời gian thực thi.
Dưới đây là một số kỹ thuật vector hóa thường gặp và ví dụ:
Phép toán số học:datacamp_rows[‘total’] = datacamp_rows[‘price’] * datacamp_rows[quantity’]
Logic điều kiện:datacamp_rows[‘flag’] = np.where(datacamp_rows[‘value’] > 10, ‘high’, ‘low’)
Phương thức chuỗi:datacamp_rows[‘cleaned’] = datacamp_rows[‘text’].str.lower().str.strip()
Xử lý thời gian:datacamp_rows[‘year’] =datacamp_rows[‘date’].dt.year
Các phép toán vector hóa được hỗ trợ bởi mã C biên dịch sẵn và quản lý bộ nhớ tối ưu, thường vượt trội so với vòng lặp Python, đặc biệt với DataFrame lớn.
Giải pháp trung gian: .apply() và xử lý song song
Khi triển khai logic theo hàng, khuyến nghị dùng .apply(axis=1). Dù không nhanh bằng vector hóa, nó hiệu quả và biểu đạt hơn lặp theo hàng. .apply() đôi khi chậm trên DataFrame lớn vì vẫn lặp nội bộ trong C. Tuy nhiên, nó chấp nhận được cho logic mức độ vừa.
Có nhiều công cụ bạn có thể cân nhắc để tối ưu .apply(), như:
Swifter: Tự động quyết định cách thực thi .apply() nhanh nhất.
Pandarallel: Giúp bạn dễ dàng thực thi song song .apply() trên nhiều lõi CPU chỉ với một dòng lệnh.
Numba: Trình biên dịch JIT tăng tốc các hàm số học Python. Khi dùng bên trong .apply(), có thể giảm mạnh thời gian tính toán cho thao tác số học nặng.
Dùng các cột trung gian cho biến đổi hiệu quả
Một chiến lược mạnh trong Pandas là tạo các cột tạm để chia nhỏ thao tác phức tạp thành các bước vector hóa dễ quản lý, tránh cần lặp tường minh theo từng hàng.
Phân rã logic nhiều bước: Thay vì áp dụng logic phức tạp một lần, hãy chia ra nhiều cột.
Dùng cờ hoặc phân loại hỗ trợ: Dùng cột boolean hoặc phân loại để lọc, nhóm, hoặc áp dụng điều kiện.
Tránh dư thừa: Lưu trữ kết quả trung gian để tránh tính toán lặp đi lặp lại, cải thiện khả năng đọc và hiệu năng.
Xóa hoặc đổi tên sau: Khi xử lý xong, loại bỏ các cột trung gian hoặc đổi tên đầu ra cuối cho rõ ràng.
Kỹ thuật tối ưu hiệu năng và benchmark
Có nhiều chiến lược tối ưu và benchmark so sánh để bảo đảm khả năng mở rộng và sử dụng bộ nhớ hiệu quả, đặc biệt khi làm việc với tập dữ liệu lớn.
Phân tích so sánh các phương pháp lặp
Các phương pháp lặp trong Python có hiệu năng khác nhau. Ví dụ, vòng lặp for và while, khi kết hợp với các phương thức Pandas như .itertuples() và .iterrows(), chậm đáng kể so với các phép toán vector hóa.
Benchmark thường cho thấy .itertuples() nhanh và tiết kiệm bộ nhớ hơn .iterrows() vì trả về namedtuple thay vì Series. Các phép toán vector hóa vượt trội hơn mọi hình thức lặp khác do triển khai nền tảng bằng C.
Khi dữ liệu mở rộng đến hàng triệu hàng, các khác biệt này trở nên then chốt vì phương pháp kém hiệu quả có thể gây nút thắt cổ chai và tăng tiêu thụ bộ nhớ.
Chiến lược tối ưu cho tập dữ liệu lớn
Với tập dữ liệu lớn, hãy cân nhắc các kỹ thuật sau:
Xử lý theo khối (chunk): Dùng tham số chunksize trong .read_csv() để xử lý dữ liệu theo khối vừa phải thay vì nạp tất cả vào bộ nhớ một lần.
Tối ưu dtype: Thử dùng kiểu dữ liệu khác như float32 thay vì float64 để giảm bộ nhớ.
Quản lý bộ nhớ: Loại bỏ sớm các cột không dùng, lọc dữ liệu trước khi merge, và định kỳ giải phóng bộ nhớ với gc.collect().
Tính toán out-of-core: Dùng các công cụ nhưDask vàVaex để cho phép tính toán song song, out-of-core trên các tập dữ liệu vượt quá dung lượng bộ nhớ.
Ví dụ thường gặp
Có nhiều kịch bản mà lặp rất hữu ích. Dưới đây là các ví dụ thực tế minh họa mẫu lặp thường gặp và thực hành tốt khi làm việc với Pandas.
Ví dụ lặp đơn giản theo hàng
Ví dụ dưới đây cho thấy cách dùng cơ bản của .iterrows(), .itertuples(), và .apply(axis=1).
import pandas as pd
students = pd.DataFrame({"name":["Mary","Joseph"],"age":[25,30]})# Using iterrows()for index, row in students.iterrows():print(f"{row['name']} is {row['age']} years old")# Using itertuples()for row in students.itertuples(index=False):print(f"{row.name} is {row.age} years old")# Using apply()
students.apply(lambda row:print(f"{row['name']} is {row['age']} years old"), axis=1)Được hỗ trợ bởi
Mary is25 years old
Joseph is30 years old
Mary is25 years old
Joseph is30 years old
Mary is25 years old
Joseph is30 years oldĐược hỗ trợ bởi
Chỉnh sửa dữ liệu trong vòng lặp
Bạn có thể dùng các phương pháp lặp theo hàng để chỉnh sửa giá trị DataFrame trong vòng lặp; tuy nhiên, cách này không hiệu quả với tập dữ liệu lớn.
Các ví dụ sau cho thấy cách triển khai.
for index, row in students.iterrows():
students.at[index,'age']= row['age']+1
students.head()Được hỗ trợ bởi
Khi làm việc với dataframe lớn, hãy cân nhắc dùng phép toán vector hóa để tăng hiệu năng, như ví dụ dưới đây.
# Better approach using a vectorized method
students["age"]= students["age"]+1Được hỗ trợ bởi
Lọc hàng trong khi lặp
Để chỉ xử lý các hàng cụ thể, hãy dùng điều kiện trong vòng lặp, như ví dụ dưới đây, nơi các hàng có age lớn hơn 25 được in ra.
for row in students.itertuples(index=False):if row.age >25:print(f"{row.Name} is older than 25")Được hỗ trợ bởi
Tuy nhiên, cách vector hóa dưới đây tốt và hiệu quả hơn.
students_greater_than_5 = students[students["age"]>25]Được hỗ trợ bởi
Tính toán tổng hợp bằng lặp
Bạn cũng có thể tính các thống kê tóm tắt trong quá trình lặp theo hàng; tuy nhiên, Pandas cung cấp sẵn các phương thức như .sum() và .mean() nhanh hơn.
Khi lặp theo hàng trong Pandas, điều quan trọng là hiểu rõ đánh đổi giữa các phương pháp có sẵn.
Dùng .iterrows() khi bạn cần giải pháp đơn giản và không làm việc với tập dữ liệu lớn, và .itertuples() khi bạn cần lựa chọn nhanh hơn và hiệu năng cải thiện.
Luôn ưu tiên các phép toán vector hóa khi có thể, đặc biệt với tập dữ liệu lớn, vì chúng nhanh và hiệu quả hơn nhờ các thao tác nền tảng bằng C.
Dùng .apply() như phương án trung gian khi cần thao tác theo hàng hoặc cột mà khó vector hóa hoàn toàn.
Dưới đây là một số tài nguyên để học thêm về Pandas:
Giảng viên khoa học dữ liệu giàu kinh nghiệm và Nhà thống kê sinh học, có chuyên môn về Python, R và học máy.
Câu hỏi thường gặp
Có những phương pháp nào để lặp theo hàng trong Pandas?⌄
Các phương pháp lặp theo hàng trong Pandas gồm .iterrows(), .itertuples() và .apply(axis=1).
Trong những kịch bản nào nên cân nhắc lặp theo hàng?⌄
Lặp theo hàng được cân nhắc khi lấy metadata từ API bên ngoài, áp dụng logic phức tạp hoặc ghi dữ liệu theo từng hàng vào hệ thống ngoài.
Vì sao các phép toán vector hóa nhanh hơn lặp theo hàng?⌄
Các phép toán vector hóa tận dụng tối ưu hóa mức thấp được triển khai bằng C, khiến chúng nhanh hơn các phương pháp lặp theo hàng của Pandas.
Làm sao để tối ưu các phương pháp lặp theo hàng?⌄
Để tăng tốc các phương pháp lặp theo hàng, hãy cân nhắc dùng xử lý song song, triển khai kỹ thuật quản lý bộ nhớ và tối ưu dtype.
Khi nào không nên lặp theo hàng?⌄
Dù có nhiều trường hợp sử dụng, lặp theo hàng không được khuyến khích khi có thể thực hiện phép toán vector hóa, tập dữ liệu lớn, hoặc có nhiều điều kiện hay vòng lặp lồng áp dụng lên DataFrame.
Khi bạn cần thực hiện các thao tác trên Pandas DataFrame theo từng hàng, bạn sẽ cần dùng đến lặp hàng. Dù Pandas được tối ưu cho các phép toán vector hóa, lặp theo hàng vẫn thiết yếu khi áp dụng logic không thể vector hóa, đặc biệt trong các thao tác dữ liệu phức tạp hoặc xử lý điều kiện theo từng hàng.
Có nhiều phương pháp bạn có thể áp dụng cho một Pandas DataFrame để lặp qua các hàng.
.iterrows(): Dùng cho các thao tác đơn giản theo hàng, khi cần cả chỉ mục và dữ liệu hàng. Trả về cặp index-series, có thể chậm với dataframe lớn và không phù hợp cho tính toán nặng..itertuples(): Dùng như một lựa chọn nhanh hơn.iterrows(), nhất là khi bạn không cần Pandas Series. Trả về namedtuple các giá trị hàng và tiết kiệm bộ nhớ hơn.iterrows()..apply(axis=1): Áp dụng một hàm cho từng hàng, thường dùng với đối sốaxis = 1. Chậm hơn các phương pháp vector hóa, nhưng thường nhanh hơn vòng lặp tường minh.Hiểu về lặp theo hàng trong Pandas DataFrame
Mặc dù Pandas được thiết kế để hoạt động tối ưu với các phép toán theo cột, nhiều phương pháp Python hỗ trợ lặp theo hàng, đặc biệt khi làm việc với từng hàng riêng lẻ.
Cơ chế nền tảng của lặp theo hàng
Pandas làm việc với DataFrame theo định dạng cột, nhờ đó hiệu quả khi áp dụng các biến đổi đồng thời cho các cột của DataFrame.
Đây cũng là một trong các lý do vì sao các phép toán vector hóa hiệu quả trong Pandas và thường được khuyến khích thay vì lặp theo hàng, vốn có thể chậm khi làm việc với DataFrame lớn.
Dưới đây là các phương pháp lặp theo hàng chủ đạo:
.iterrows(): Trả về mỗi hàng như một bộ(index, Series)..itertuples(): Nhanh hơn.iterrows()và trả về mỗi hàng như một namedtuple..items(): Không phải lặp theo hàng, mà lặp qua các cột của Pandas DataFrame, trả về nhãn cột và Series, thường dùng cho các thao tác theo cột.Đánh đổi hiệu năng của các cách tiếp cận lặp
Dựa trên benchmark với DataFrame cỡ vừa 100.000 hàng,
.itertuples()nhanh hơn.iterrows()khoảng 5–10 lần về tốc độ và hiệu quả bộ nhớ. Lý do là.itertuples()tránh tạo đối tượng Series cho từng hàng và chỉ trả về namedtuple gọn nhẹ.Các phép toán vector hóa nhanh hơn mọi hình thức lặp vì được triển khai bằng mã C tối ưu. Chúng loại bỏ vòng lặp ở cấp Python, giảm overhead. Ví dụ, cộng hai cột bằng
datacamp_rows[“A”] +nhanh hơn dùng vòng lặpdatacamp_rows[“B”]forvới.iterrows()..iterrows()có footprint bộ nhớ lớn vì trả về một đối tượng Pandas Series hoàn chỉnh, và các Series này có thể gặp vấn đề không nhất quán dtype do bắt nguồn từ các cột có kiểu dữ liệu khác nhau.Với tập dữ liệu nhỏ, khuyến nghị dùng
.iterrows(), còn với tập dữ liệu lớn hơn, bạn có thể dùng.itertuples().Khi nào và vì sao nên lặp qua các hàng của DataFrame
Bạn có thể gặp tình huống không thể áp dụng phép toán vector hóa và buộc phải quay về lặp theo hàng. Trong những tình huống như vậy, phần này sẽ giúp bạn biết khi nào nên và không nên dùng lặp theo hàng.
Các trường hợp sử dụng điển hình của lặp theo hàng
Các tình huống điển hình gồm:
Khi không nên lặp: lưu ý và phương án thay thế
Dù có các trường hợp sử dụng, bạn nên tránh lặp theo hàng trong các trường hợp sau:
Thay vì lặp, cân nhắc các phương án sau:
Dùng các phép toán vector hóa bất cứ khi nào có thể.
Tận dụng
.apply()với hàm được tối ưu cho các tác vụ phức tạp nhưng vẫn có thể vector hóa phần nào.Cân nhắc xử lý theo lô hoặc song song nếu buộc phải lặp nhưng bị ràng buộc hiệu năng.
Bạn cần tránh các sai lầm thường gặp của vòng lặp theo hàng như:
.iterrows()trả về bản sao, không phải tham chiếu tới hàng gốc; do đó sửa đổi nó không làm thay đổi DataFrame ban đầu.Khó đọc và bảo trì hơn so với các phép toán vector hóa.
Các phương pháp phổ biến để lặp qua hàng trong Pandas
Bạn có thể triển khai lặp theo hàng trong Pandas DataFrame bằng nhiều phương pháp, tùy thuộc vào trường hợp sử dụng hoặc bản chất của DataFrame. Dưới đây là các phương pháp để lặp qua hàng của Pandas DataFrame.
Sử dụng .iterrows()
Phương thức
.iterrows()bao gồm việc lặp qua từng hàng của DataFrame. Cú pháp như sau:Trong đó
datacamp_rowslà dataframe được lặp,indexlà chỉ mục hàng, vàrowlà Pandas Series chứa dữ liệu của hàng.Ví dụ sử dụng cơ bản:
Phương thức
.iterrows()trả về một generator tạo ra chỉ mục của hàng cùng với một đối tượng Series đại diện cho hàng. Các khóa của Series này là tên cột, và giá trị là dữ liệu tương ứng ở mỗi hàng.Bên trong,
.iterrows()trả về như sau.Sử dụng .itertuples()
.itertuples()nhanh và tiết kiệm bộ nhớ hơn.iterrows(), đồng thời trả về mỗi hàng dưới dạng namedtuple, cho phép truy cập giá trị cột bằng dot notation. Cú pháp như sau:Trong đó
index=Truebao gồm chỉ mục DataFrame như phần tử đầu tiên của mỗi tuple, vàname="Pandas"đặt tên lớp namedtuple trả về. Nếuname=None, vòng lặpfortrả về tuple thông thường không thể truy cập thuộc tính.Ví dụ thực tế cách
.itertuples()hoạt động:.itertuples()trả về một generator tạo ra các namedtuple, trong đó mỗi hàng được biểu diễn như một đối tượng gọn nhẹ.Bạn có thể truy cập từng trường hàng bằng dot notation, như
row.Namevàrow.age, đi kèm chỉ mục ở trước.Bên trong, nó trả về như sau:
Sử dụng .apply() cho thao tác theo hàng
Phương thức
.apply()trong Pandas hữu ích khi áp dụng hàm cho từng hàng để thực hiện lặp theo hàng, như khi dùng tham sốaxis=1. Cú pháp như sau:Trong đó hàm áp dụng cho hàng là
func, và đối sốaxis=1được thiết lập.Dưới đây là ví dụ minh họa cách áp dụng.
Dùng phương thức
.apply()khi tạo cột mới dựa trên các cột hiện có, hoặc khi áp dụng phép tính hay biến đổi tùy chỉnh.Về lặp theo hàng, bạn có thể dùng nó để tạo logic điều kiện theo hàng như if-else. Khi đặt
axis=1, hàm được truyền một Series với tên cột làm chỉ mục. Hàm này xử lý các hàng và trả về một giá trị vô hướng trong cột mới hoặc Series trong nhiều cột.Dù
.apply(axis=1)chậm hơn các phép toán vector hóa, nó nhanh và gọn hơn.iterrows().Dùng DataFrame.index với loc/iloc để lặp thủ công
Một cách khác để lặp theo hàng là bạn dùng
.loc[]hoặc.iloc[]thủ công với vòng lặpforđể lặp qua một Pandas DataFrame.Cách này hoạt động tương tự các phương thức
.iterrows()hoặc.itertuples(). Ưu điểm là bạn có toàn quyền kiểm soát các hàng. Cú pháp như sau:Dưới đây là ví dụ thực tế cách triển khai.
Một trong các trường hợp sử dụng là khi bạn cần kiểm soát chính xác thứ tự hàng, hoặc khi viết logic từng bước để gỡ lỗi. Dù vậy, cách này kém hiệu quả với dataframe lớn và cũng chậm hơn các phép toán vector hóa.
Cần dùng
.loc[]khi bạn cần tra cứu theo nhãn hoặc.iloc[]khi cần truy cập theo vị trí, đặc biệt với các vòng lặp theo range.So sánh .iterrows(), .itertuples(), và .apply()
Dưới đây là bảng tóm tắt khác biệt giữa ba phương pháp.
Tính năng
iterows()
itertuples()
apply(axis=1)
Cú pháp
for idx, row in df.iterrows:
for row in df.itertuples():
df.apply(func, axis=1)
Đầu ra
(index, Series)
namedtuple
Trả về giá trị của hàm (vô hướng hoặc Series)
Tốc độ
Chậm
Nhanh nhất
Trung bình
Sử dụng bộ nhớ
Trung bình
Thấp
Trung bình
Dễ đọc
Trung bình
Cao
Cao
Trường hợp phù hợp
Dựng thử nhanh hoặc gỡ lỗi
Tập dữ liệu lớn
Suy dẫn cột
Hạn chế
Chậm
Không xử lý được logic hàng phức tạp
Chậm hơn vector hóa hoàn toàn
Phương thức .iterrows(): Phân tích chi tiết và trường hợp sử dụng
Mặc dù
.iterrows()là cách trực quan để lặp qua các hàng của Pandas DataFrame, nó có những hạn chế có thể ảnh hưởng hiệu năng.Đặc điểm triển khai và hạn chế
Lặp với
.iterrows()trả về mỗi hàng của DataFrame như một bộ gồm chỉ mục hàng và một đối tượng Series chứa dữ liệu trong hàng.Dù đơn giản, nó có nhược điểm về chuyển đổi dtype; ví dụ, có thể chuyển số nguyên thành số thực nếu Series cần chứa kiểu hỗn hợp, dễ gây lỗi tinh vi trong tính toán hoặc so sánh.
Ngoài ra, vì
.iterrows()trả về Series cho mỗi hàng, dẫn tới overhead bộ nhớ, khiến hiệu năng chậm hơn so với các phép toán vector hóa.Việc sửa dữ liệu trong vòng lặp dùng
.iterrows()không được khuyến khích, vì thay đổi trên Series không tác động ngược lại dataframe.Ứng dụng phù hợp và cách khắc phục
Bất chấp các hạn chế trên,
.iterrows()vẫn hữu ích trong một số tình huống như:.iterrows()cho các thao tác không thể vector hóa như gọi API, ghi file hoặc tương tác cơ sở dữ liệu theo từng hàng..iterrows().Để giữ tính nhất quán dtype, cân nhắc chuyển sang
.itertuples(), vì nó trả về namedtuple không chuyển đổi kiểu.Phương thức .itertuples(): Lặp tối ưu hiệu năng
.itertuples()nhanh và tiết kiệm bộ nhớ hơn.iterrows()vì trả về namedtuple. Hãy xem một số đặc điểm khiến nó vượt trội hơn.iterrows().Triển khai kỹ thuật và ưu điểm
Một số ưu điểm của
.itertuples()gồm:Tăng hiệu năng: Thay vì tạo đối tượng Series như
.iterrows()vốn tốn bộ nhớ và giảm hiệu năng,.itertuples()tránh overhead bộ nhớ và cải thiện hiệu năng bằng generator trả về namedtuple.Tùy biến: Đối số
index=Falsetrong.itertuples()loại bỏ chỉ mục khỏi tuple, và thiết lậpname= 'Custom'cho phép đặt tên lớpnamedtupletùy chỉnh, cải thiện khả năng đọc hoặc tích hợp với hệ thống khác.Mẫu sử dụng thực tế và hạn chế
Khi dùng
.itertuples(), cần lưu ý các hạn chế sau.Ràng buộc đặt tên cột: Tên cột chứa ký tự đặc biệt hoặc khoảng trắng có thể tạo ra định danh Python không hợp lệ. Những tên này sẽ được chỉnh thành hợp lệ hoặc truy cập bằng giải nén tuple theo chỉ số.
Bất biến:
Namedtuplelà bất biến, nghĩa là bạn không thể sửa giá trị tại chỗ. Điều này ngụ ý mọi biến đổi cần xây dựng cấu trúc mới hoặc thu thập giá trị mong muốn vào danh sách hay dataframe khác.Một số thực hành tốt khi dùng
.itertuples():Các phương án thay thế lặp theo hàng: Vector hóa và hơn thế
Dù các phương pháp lặp theo hàng chủ yếu là
.iterrows()và.itertuples(), pandas cung cấp các lựa chọn khác hiệu quả hơn cho xử lý dữ liệu quy mô lớn, như vector hóa, vốn tiết kiệm bộ nhớ và nhanh hơn.Phép toán vector hóa: cách tiếp cận tối ưu
Phép toán vector hóa áp dụng thao tác trên toàn bộ mảng hoặc cột DataFrame cùng lúc, tận dụng tối ưu hóa mức thấp trong NumPy và Pandas. Cách này gọn gàng, dễ đọc và giảm mạnh thời gian thực thi.
Dưới đây là một số kỹ thuật vector hóa thường gặp và ví dụ:
Phép toán số học:
datacamp_rows[‘total’] =datacamp_rows[‘price’] *datacamp_rows[quantity’]Logic điều kiện:
datacamp_rows[‘flag’] = np.where(datacamp_rows[‘value’] > 10, ‘high’, ‘low’)Phương thức chuỗi:
datacamp_rows[‘cleaned’] =datacamp_rows[‘text’].str.lower().str.strip()Xử lý thời gian:
datacamp_rows[‘year’] =datacamp_rows[‘date’].dt.yearCác phép toán vector hóa được hỗ trợ bởi mã C biên dịch sẵn và quản lý bộ nhớ tối ưu, thường vượt trội so với vòng lặp Python, đặc biệt với DataFrame lớn.
Giải pháp trung gian: .apply() và xử lý song song
Khi triển khai logic theo hàng, khuyến nghị dùng
.apply(axis=1). Dù không nhanh bằng vector hóa, nó hiệu quả và biểu đạt hơn lặp theo hàng..apply()đôi khi chậm trên DataFrame lớn vì vẫn lặp nội bộ trong C. Tuy nhiên, nó chấp nhận được cho logic mức độ vừa.Có nhiều công cụ bạn có thể cân nhắc để tối ưu
.apply(), như:Swifter: Tự động quyết định cách thực thi
.apply()nhanh nhất.Pandarallel: Giúp bạn dễ dàng thực thi song song
.apply()trên nhiều lõi CPU chỉ với một dòng lệnh.Numba: Trình biên dịch JIT tăng tốc các hàm số học Python. Khi dùng bên trong
.apply(), có thể giảm mạnh thời gian tính toán cho thao tác số học nặng.Dùng các cột trung gian cho biến đổi hiệu quả
Một chiến lược mạnh trong Pandas là tạo các cột tạm để chia nhỏ thao tác phức tạp thành các bước vector hóa dễ quản lý, tránh cần lặp tường minh theo từng hàng.
Kỹ thuật tối ưu hiệu năng và benchmark
Có nhiều chiến lược tối ưu và benchmark so sánh để bảo đảm khả năng mở rộng và sử dụng bộ nhớ hiệu quả, đặc biệt khi làm việc với tập dữ liệu lớn.
Phân tích so sánh các phương pháp lặp
Các phương pháp lặp trong Python có hiệu năng khác nhau. Ví dụ, vòng lặp for và while, khi kết hợp với các phương thức Pandas như
.itertuples()và.iterrows(), chậm đáng kể so với các phép toán vector hóa.Benchmark thường cho thấy
.itertuples()nhanh và tiết kiệm bộ nhớ hơn.iterrows()vì trả về namedtuple thay vì Series. Các phép toán vector hóa vượt trội hơn mọi hình thức lặp khác do triển khai nền tảng bằng C.Khi dữ liệu mở rộng đến hàng triệu hàng, các khác biệt này trở nên then chốt vì phương pháp kém hiệu quả có thể gây nút thắt cổ chai và tăng tiêu thụ bộ nhớ.
Chiến lược tối ưu cho tập dữ liệu lớn
Với tập dữ liệu lớn, hãy cân nhắc các kỹ thuật sau:
Xử lý theo khối (chunk): Dùng tham số
chunksizetrong.read_csv()để xử lý dữ liệu theo khối vừa phải thay vì nạp tất cả vào bộ nhớ một lần.Tối ưu dtype: Thử dùng kiểu dữ liệu khác như
float32thay vìfloat64để giảm bộ nhớ.Quản lý bộ nhớ: Loại bỏ sớm các cột không dùng, lọc dữ liệu trước khi merge, và định kỳ giải phóng bộ nhớ với
gc.collect().Tính toán out-of-core: Dùng các công cụ như Dask và Vaex để cho phép tính toán song song, out-of-core trên các tập dữ liệu vượt quá dung lượng bộ nhớ.
Ví dụ thường gặp
Có nhiều kịch bản mà lặp rất hữu ích. Dưới đây là các ví dụ thực tế minh họa mẫu lặp thường gặp và thực hành tốt khi làm việc với Pandas.
Ví dụ lặp đơn giản theo hàng
Ví dụ dưới đây cho thấy cách dùng cơ bản của
.iterrows(),.itertuples(), và.apply(axis=1).Chỉnh sửa dữ liệu trong vòng lặp
Bạn có thể dùng các phương pháp lặp theo hàng để chỉnh sửa giá trị DataFrame trong vòng lặp; tuy nhiên, cách này không hiệu quả với tập dữ liệu lớn.
Các ví dụ sau cho thấy cách triển khai.
Khi làm việc với dataframe lớn, hãy cân nhắc dùng phép toán vector hóa để tăng hiệu năng, như ví dụ dưới đây.
Lọc hàng trong khi lặp
Để chỉ xử lý các hàng cụ thể, hãy dùng điều kiện trong vòng lặp, như ví dụ dưới đây, nơi các hàng có
agelớn hơn25được in ra.Tuy nhiên, cách vector hóa dưới đây tốt và hiệu quả hơn.
Tính toán tổng hợp bằng lặp
Bạn cũng có thể tính các thống kê tóm tắt trong quá trình lặp theo hàng; tuy nhiên, Pandas cung cấp sẵn các phương thức như
.sum()và.mean()nhanh hơn.Kết luận
Khi lặp theo hàng trong Pandas, điều quan trọng là hiểu rõ đánh đổi giữa các phương pháp có sẵn.
Dùng
.iterrows()khi bạn cần giải pháp đơn giản và không làm việc với tập dữ liệu lớn, và.itertuples()khi bạn cần lựa chọn nhanh hơn và hiệu năng cải thiện.Luôn ưu tiên các phép toán vector hóa khi có thể, đặc biệt với tập dữ liệu lớn, vì chúng nhanh và hiệu quả hơn nhờ các thao tác nền tảng bằng C.
Dùng
.apply()như phương án trung gian khi cần thao tác theo hàng hoặc cột mà khó vector hóa hoàn toàn.Dưới đây là một số tài nguyên để học thêm về Pandas:
Bạn cũng có thể xem các trang khóa học sau để tăng tốc học tập: