【问题标题】:Random Sampling in Google BigQueryGoogle BigQuery 中的随机抽样
【发布时间】:2014-06-16 00:40:33
【问题描述】:

我刚刚发现 RAND() 函数虽然没有记录在案,但在 BigQuery 中也可以使用。我能够使用以下方法从莎士比亚数据集中生成(看似)10 个单词的随机样本:

SELECT word FROM
(SELECT rand() as random,word FROM [publicdata:samples.shakespeare] ORDER BY random)
LIMIT 10

我的问题是:使用这种方法代替参考手册“高级示例”部分中定义的 HASH() 方法有什么缺点吗? https://developers.google.com/bigquery/query-reference

【问题讨论】:

标签: google-cloud-platform google-bigquery


【解决方案1】:

BigQuery 最近推出了抽样选项,让我们可以从大型 BigQuery 表中随机查询数据子集。我们还可以提及记录的百分比。

例子:

SELECT * FROM dataset.my_table TABLESAMPLE SYSTEM (10 PERCENT)

SELECT *
FROM dataset.table1 T1 TABLESAMPLE SYSTEM (10 PERCENT)
JOIN dataset.table2 T2 TABLESAMPLE SYSTEM (20 PERCENT) ON customer_id

https://cloud.google.com/bigquery/docs/table-sampling

【讨论】:

  • 这似乎比其他方法运行得慢。不知道为什么。
【解决方案2】:

一旦你计算出你需要多少总数,你就可以明智地......

如前所述,一种方法是随机进行非确定性(每次运行 = 不同样本),例如,如果您希望对总数据库进行 0.1% 的采样,您会这样做:

SELECT *
FROM `dataset.table`
WHERE RAND() < 0.001 

您实际上可以通过保存此表来使其具有确定性,以便以后查询它,您也可以只选择一个键列并仅保存以供将来使用。


另一种获得相同可重复随机样本的方法是使用加密散列函数生成(唯一标识符字段)列的指纹,然后根据指纹的两位数选择行。下面将标记一个占总数据库 70% 的随机样本。之后您可以在 in_sample = True 上过滤表:

SELECT
*,
IF(MOD(ABS(FARM_FINGERPRINT(CAST(YOUR_COLUMN AS STRING))), 100) < 70,'True', 'False') 
AS in_sample
FROM (
     SELECT
     DISTINCT(YOUR_UNIQUE_IDENTIFIER_COLUMN) AS YOUR_COLUMN
     FROM
     `dataset.table`)

如果您没有唯一标识符列,您可以将多个列连接成一个。


与上述类似,但具有散列函数。可重复并为您提供 70% 的样品。如果您想要其他数字,只需将 7 更改为您想要的 %:

SELECT
*
FROM
`dataset.table`
WHERE
ABS(HASH(YOUR_COLUMN)) % 10 < 7

不知道指纹与哈希的可扩展性,所以两者都提到了,对于某些人来说,一个可能比另一个更好。

祝你好运,

【讨论】:

    【解决方案3】:

    对于分层抽样,请查看https://stackoverflow.com/a/52901452/132438


    很好地找到它:)。我最近请求了这个函数,但它还没有进入文档。

    我会说 RAND() 的优点是结果会有所不同,而 HASH() 将继续为相同的值提供相同的结果(随着时间的推移不能保证,但你明白了)。

    如果您希望 RAND() 带来的可变性同时仍然获得一致的结果 - 您可以使用整数作为种子,如 RAND(3)。

    请注意,尽管您粘贴的示例正在执行完整排序的随机值 - 对于足够大的输入,此方法无法扩展。

    一种可扩展的方法,获得大约 10 个随机行:

    SELECT word
    FROM [publicdata:samples.shakespeare]
    WHERE RAND() < 10/164656
    

    其中 10 是我想要获得的近似结果数,而 164656 是该表的行数


    标准 SQL 更新:

    #standardSQL
    SELECT word
    FROM `publicdata.samples.shakespeare`
    WHERE RAND() < 10/164656
    

    甚至:

    #standardSQL
    SELECT word
    FROM `publicdata.samples.shakespeare`
    WHERE RAND() < 10/(SELECT COUNT(*) FROM `publicdata.samples.shakespeare`)
    

    【讨论】:

    • 嗨菲利普!你能解释一下你在用WHERE RAND() &lt; 10/164656做什么吗?谢谢!
    • RAND() 给了我一个介于 0 和 1 之间的随机数。因此,如果我要求一组随机数,其中只有大约十分之一会小于 0.1,只有大约百分之一将小于 0.01,依此类推。莎士比亚表有 164656 行。如果我只想要大约 1 个随机行,我会给每一行一个随机数,然后选择小于 1/164656 的那些。不能保证会有一个 - 但仍然存在。 10? 10*1/164656=10/164656。试试看:)。
    • @FelipeHoffa 我正在尝试实现您的方法,但得到的结果却大相径庭。我有一个大约 60 亿行的表,在我使用例如进行采样之后rand() &lt; 0.004,样本大小与总行数的比率为0.0002。换句话说,我的样本比预期的要小大约 20 倍。你对这种行为有解释吗?
    • 60 亿 * 0.004 = 2400 万。如果我在约 60 亿条记录表上尝试它,我会得到超过 2300 万行。对我有用: SELECT COUNT(*) FROM ( SELECT requests FROM [fh-bigquery:wikipedia.pagecounts_201410] WHERE RAND()
    • @FelipeHoffa 你说得对。我之前一定犯了一个错误,因为我今天早上又试了一次,现在它可以正常工作了。谢谢!
    【解决方案4】:

    一个更简单的提示:您可以通过它自己的功能订购,即:

    选择 x 从 y 按 rand() 排序 限制 100

    => 100 个样本

    【讨论】:

    • 正确。但是,可以利用select x from (select rand() as r, x from y order by r limit 100);
    【解决方案5】:

    很高兴知道 RAND() 可用!

    就我而言,我需要一个预定义的样本大小。我不需要知道总行数并对总行进行除法样本大小,而是使用以下查询:

    SELECT word, rand(5) as rand
    FROM [publicdata:samples.shakespeare]
    order by rand
    #Sample size needed = 10
    limit 10
    

    总而言之,我使用 ORDER BY + LIMIT 随机化,然后提取定义数量的样本。

    【讨论】:

    • 请注意,使用ORDER BY MD5(someIdentifier) 可以实现“半随机但确定性”排序
    猜你喜欢
    • 2019-03-24
    • 1970-01-01
    • 1970-01-01
    • 2016-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多