如何读取带有熊猫坏行的 CSV 的最后 n 列?

How can I read the last n columns of a CSV with bad lines with pandas?

提问人:Diego H 提问时间:11/14/2023 最后编辑:Diego H 更新时间:11/21/2023 访问量:61

问:

我在尝试使用 pandas 读取 CSV 文件时遇到了一个问题。CSV 结构如下:

Col1, Col2, Col3, Col4, Col5
a1, a2, a3, a4, a5
b1, b2, b3, b4, b5
c1, c3, c4, c5
d1, d2, d3, d4, d5

有些行包含缺失值,我特别想只提取每行的最后一个单元格,因为这些单元格是肯定存在的。在给定的示例中,其中 ,所需的 DataFrame 应如下所示:nn=3

    Col3 Col4 Col5
0   a3   a4   a5
1   b3   b4   b5
2   c3   c4   c5
3   d3   d4   d5

我尝试使用 usecols=[2, 3, 4],但它导致了 N/A 值:

   Col3  Col4  Col5
0    a3    a4    a5
1    b3    b4    b5
2    c4    c5   NaN
3    d3    d4    d5

关于如何实现预期结果的任何指导将不胜感激。感谢您的帮助!

python pandas csv 缺失数据

评论

1赞 furas 11/14/2023
计算机不是那么聪明,知道你在行中丢失了。它可能需要使用标准 来解决它。最终,您可能必须自行迭代行并将单元格移动到右侧。c2open()read()DataFrame
1赞 Jab 11/14/2023
相反,如果您失踪了怎么办?你怎么知道你错过了什么?c2c5
0赞 RomanPerekhrest 11/14/2023
此行的预期结果是什么:使用 ?c1, , c3, , c5n=3
0赞 Timeless 11/14/2023
@DiegoH,您的 I/O 不匹配!在你预期的输出中,从哪里来?Col5

答:

1赞 mozway 11/14/2023 #1

很难直接在read_csv层面处理这个问题。一个选项可能是加载所有数据,然后重新对齐它:

df = pd.read_csv(data)

mask = df.notna().loc[:, ::-1].cummax(axis=1).loc[:, ::-1]

out = pd.DataFrame(df.to_numpy()[np.arange(len(df))[:,None],
                                 np.argsort(mask)],
                   index=df.index, columns=df.columns
                  )

输出:

   Col1  Col2  Col3  Col4
a1   a2    a3    a4    a5
b1   b2    b3    b4    b5
c1  NaN    c3    c4    c5
d1   d2    d3    d4    d5

然后,您可以仅选择所需的列

如果您只想处理最后几列:n

last_col = 3

mask = df.notna().iloc[:, :-last_col-1:-1].cummax(axis=1).iloc[:, ::-1]

out = df.copy()
out.iloc[:, -last_col:] = (df
                     .iloc[:, -last_col:]
                     .to_numpy()[np.arange(len(df))[:,None],
                                 np.argsort(mask)])

输出:

   Col1  Col2  Col3  Col4
a1   a2    a3    a4    a5
b1   b2    b3    b4    b5
c1   c3   NaN    c4    c5
d1   d2    d3    d4    d5
2赞 Timeless 11/14/2023 #2

为了好玩,您可以尝试使用正则表达式分隔符:

N = 3 # last N columns

pat = r".+?{}?$".format("([^,]+),"*N)

df = pd.read_csv(file, sep=pat, engine="python").dropna(how="all", axis=1)

输出:

print(df)

   Col2  Col3  Col4
0    a3    a4    a5
1    b3    b4    b5
2    c3    c4    c5
3    d3    d4    d5

评论

0赞 Diego H 11/14/2023
喜欢这个把戏,效果很好!
0赞 CodeMaven42 11/14/2023 #3

如果您只想提取每行最后一个单元格的值,则可以使用以下代码获取每行的最后一个单元格。

法典:

import pandas as pd
from io import StringIO

csv_data = """
Col1, Col2, Col3, Col4
a1, a2, a3, a4, a5
b1, b2, b3, b4, b5
c1, c3, c4, c5
d1, d2, d3, d4, d5
"""

df = pd.read_csv(StringIO(csv_data))

last_values = df.apply(lambda row: row.dropna().iloc[-1] if not row.dropna().empty else pd.NA, axis=1)

for _, value in zip(last_values.index, last_values):
    print(value)

“df = pd.read_csv(StringIO(csv_data))” 此行使用 pd.read_csv 函数将 CSV 数据读入 Pandas DataFrame (df)。StringIO(csv_data) 用于将字符串csv_data转换为pd.read_csv可以读取的类似文件的对象。

“last_values = df.apply(lambda row: row.dropna().iloc[-1] if not row.dropna().empty else pd.NA, 轴=1)” 在这里,通过将 lambda 函数应用于 DataFrame (df) 的每一行,创建了一个名为 last_values 的新 Series。lambda 函数使用 row.dropna() 检查该行是否具有任何非 null 值。如果它不为空,则使用 iloc[-1] 提取最后一个非 null 值。如果该行为空,则分配 pd。NA(Pandas 对缺失值的表示)。

" 对于 _,zip(last_values.index, last_values) 中的值: print(值) " 最后,循环遍历 last_values 系列的索引和值,并打印每个值。此循环实质上是打印原始 DataFrame 每行中的最后一个非 null 值。

1赞 JonSG 11/14/2023 #4

如果 pandas 不是必需的,我想我会使用 CSV 包和默认阅读器来挑选每行的最后三列:

像这样:

import io
import csv

data = """
Col1,Col2,Col3,Col4
a1,a2,a3,a4,a5
b1,b2,b3,b4,b5
c1,c3,c4,c5
d1,d2,d3,d4,d5
""".strip()

with io.StringIO(data) as file_in:
    reader = csv.reader(file_in)
    headers = next(reader)  # not sure if you want/nead the header
    rows = [row[-3:] for row in reader] # the last three columns

现在你可以做你喜欢的事情了rows

for row in rows:
    print(row)

会给你:

['a3', 'a4', 'a5']
['b3', 'b4', 'b5']
['c3', 'c4', 'c5']
['d3', 'd4', 'd5']